Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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/>.
16
 
17
/**
18
 * External message API
19
 *
20
 * @package    core_message
21
 * @category   external
22
 * @copyright  2011 Jerome Mouneyrac
23
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24
 */
25
 
26
use core_external\external_api;
27
use core_external\external_format_value;
28
use core_external\external_function_parameters;
29
use core_external\external_multiple_structure;
30
use core_external\external_single_structure;
31
use core_external\external_value;
32
use core_external\external_warnings;
33
use core_external\util;
34
 
35
defined('MOODLE_INTERNAL') || die();
36
 
37
require_once($CFG->dirroot . "/message/lib.php");
38
 
39
/**
40
 * Message external functions
41
 *
42
 * @package    core_message
43
 * @category   external
44
 * @copyright  2011 Jerome Mouneyrac
45
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
46
 * @since Moodle 2.2
47
 */
48
class core_message_external extends external_api {
49
    /**
50
     * Returns description of method parameters
51
     *
52
     * @return external_function_parameters
53
     * @since Moodle 3.6
54
     */
55
    public static function send_messages_to_conversation_parameters() {
56
        return new external_function_parameters(
57
            array(
58
                'conversationid' => new external_value(PARAM_INT, 'id of the conversation'),
59
                'messages' => new external_multiple_structure(
60
                    new external_single_structure(
61
                        array(
62
                            'text' => new external_value(PARAM_RAW, 'the text of the message'),
63
                            'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
64
                        )
65
                    )
66
                )
67
            )
68
        );
69
    }
70
 
71
    /**
72
     * Send messages from the current USER to a conversation.
73
     *
74
     * This conversation may be any type of conversation, individual or group.
75
     *
76
     * @param int $conversationid the id of the conversation to which the messages will be sent.
77
     * @param array $messages An array of message to send.
78
     * @return array the array of messages which were sent (created).
79
     * @since Moodle 3.6
80
     */
81
    public static function send_messages_to_conversation(int $conversationid, array $messages = []) {
82
        global $CFG, $USER;
83
 
84
        // Check if messaging is enabled.
85
        if (empty($CFG->messaging)) {
86
            throw new moodle_exception('disabled', 'message');
87
        }
88
 
89
        // Ensure the current user is allowed to run this function.
90
        $context = context_system::instance();
91
        self::validate_context($context);
92
 
93
        $params = self::validate_parameters(self::send_messages_to_conversation_parameters(), [
94
            'conversationid' => $conversationid,
95
            'messages' => $messages
96
        ]);
97
 
98
        // Validate messages content before posting them.
99
        foreach ($params['messages'] as $message) {
100
            // Check message length.
101
            if (strlen($message['text']) > \core_message\api::MESSAGE_MAX_LENGTH) {
102
                throw new moodle_exception('errormessagetoolong', 'message');
103
            }
104
        }
105
 
106
        $messages = [];
107
        foreach ($params['messages'] as $message) {
108
            $createdmessage = \core_message\api::send_message_to_conversation($USER->id, $params['conversationid'], $message['text'],
109
                $message['textformat']);
110
            $createdmessage->text = message_format_message_text((object) [
111
                'smallmessage' => $createdmessage->text,
112
                'fullmessageformat' => util::validate_format($message['textformat']),
113
                'fullmessagetrust' => $createdmessage->fullmessagetrust
114
            ]);
115
            $messages[] = $createdmessage;
116
        }
117
 
118
        return $messages;
119
    }
120
 
121
    /**
122
     * Returns description of method result value.
123
     *
124
     * @return \core_external\external_description
125
     * @since Moodle 3.6
126
     */
127
    public static function send_messages_to_conversation_returns() {
128
        return new external_multiple_structure(
129
            self::get_conversation_message_structure()
130
        );
131
    }
132
 
133
 
134
    /**
135
     * Returns description of method parameters
136
     *
137
     * @return external_function_parameters
138
     * @since Moodle 2.2
139
     */
140
    public static function send_instant_messages_parameters() {
141
        return new external_function_parameters(
142
            array(
143
                'messages' => new external_multiple_structure(
144
                    new external_single_structure(
145
                        array(
146
                            'touserid' => new external_value(PARAM_INT, 'id of the user to send the private message'),
147
                            'text' => new external_value(PARAM_RAW, 'the text of the message'),
148
                            'textformat' => new external_format_value('text', VALUE_DEFAULT, FORMAT_MOODLE),
149
                            '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),
150
                        )
151
                    )
152
                )
153
            )
154
        );
155
    }
156
 
157
    /**
158
     * Send private messages from the current USER to other users
159
     *
160
     * @param array $messages An array of message to send.
161
     * @return array
162
     * @since Moodle 2.2
163
     */
164
    public static function send_instant_messages($messages = array()) {
165
        global $CFG, $USER, $DB;
166
 
167
        // Check if messaging is enabled.
168
        if (empty($CFG->messaging)) {
169
            throw new moodle_exception('disabled', 'message');
170
        }
171
 
172
        // Ensure the current user is allowed to run this function
173
        $context = context_system::instance();
174
        self::validate_context($context);
175
        require_capability('moodle/site:sendmessage', $context);
176
 
177
        // Ensure the current user is allowed to delete message for everyone.
178
        $candeletemessagesforallusers = has_capability('moodle/site:deleteanymessage', $context);
179
 
180
        $params = self::validate_parameters(self::send_instant_messages_parameters(), array('messages' => $messages));
181
 
182
        //retrieve all tousers of the messages
183
        $receivers = array();
184
        foreach($params['messages'] as $message) {
185
            $receivers[] = $message['touserid'];
186
        }
187
        list($sqluserids, $sqlparams) = $DB->get_in_or_equal($receivers);
188
        $tousers = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams);
189
 
190
        $resultmessages = array();
191
        $messageids = array();
192
        foreach ($params['messages'] as $message) {
193
            $resultmsg = array(); //the infos about the success of the operation
194
 
195
            // We are going to do some checking.
196
            // Code should match /messages/index.php checks.
197
            $success = true;
198
 
199
            // Check the user exists.
200
            if (empty($tousers[$message['touserid']])) {
201
                $success = false;
202
                $errormessage = get_string('touserdoesntexist', 'message', $message['touserid']);
203
            }
204
 
205
            // Check message length.
206
            if ($success && strlen($message['text']) > \core_message\api::MESSAGE_MAX_LENGTH) {
207
                $success = false;
208
                $errormessage = get_string('errormessagetoolong', 'message');
209
            }
210
 
211
            // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead userid
212
            // Check if the recipient can be messaged by the sender.
213
            if ($success && !\core_message\api::can_send_message($tousers[$message['touserid']]->id, $USER->id)) {
214
                $success = false;
215
                $errormessage = get_string('usercantbemessaged', 'message', fullname(\core_user::get_user($message['touserid'])));
216
            }
217
 
218
            // Now we can send the message (at least try).
219
            if ($success) {
220
                // TODO MDL-31118 performance improvement - edit the function so we can pass an array instead one touser object.
221
                $success = message_post_message($USER, $tousers[$message['touserid']],
222
                        $message['text'], util::validate_format($message['textformat']));
223
            }
224
 
225
            // Build the resultmsg.
226
            if (isset($message['clientmsgid'])) {
227
                $resultmsg['clientmsgid'] = $message['clientmsgid'];
228
            }
229
            if ($success) {
230
                $resultmsg['msgid'] = $success;
231
                $resultmsg['timecreated'] = time();
232
                $resultmsg['candeletemessagesforallusers'] = $candeletemessagesforallusers;
233
                $messageids[] = $success;
234
            } else {
235
                // WARNINGS: for backward compatibility we return this errormessage.
236
                //          We should have thrown exceptions as these errors prevent results to be returned.
237
                $resultmsg['msgid'] = -1;
238
                if (!isset($errormessage)) { // Nobody has set a message error or thrown an exception, let's set it.
239
                    $errormessage = get_string('messageundeliveredbynotificationsettings', 'error');
240
                }
241
                $resultmsg['errormessage'] = $errormessage;
242
            }
243
 
244
            $resultmessages[] = $resultmsg;
245
        }
246
 
247
        if (!empty($messageids)) {
248
            $messagerecords = $DB->get_records_list(
249
                'messages',
250
                'id',
251
                $messageids,
252
                '',
253
                'id, conversationid, smallmessage, fullmessageformat, fullmessagetrust');
254
            $resultmessages = array_map(function($resultmessage) use ($messagerecords, $USER) {
255
                $id = $resultmessage['msgid'];
256
                $resultmessage['conversationid'] = isset($messagerecords[$id]) ? $messagerecords[$id]->conversationid : null;
257
                $resultmessage['useridfrom'] = $USER->id;
258
                $resultmessage['text'] = message_format_message_text((object) [
259
                    'smallmessage' => $messagerecords[$id]->smallmessage,
260
                    'fullmessageformat' => util::validate_format($messagerecords[$id]->fullmessageformat),
261
                    'fullmessagetrust' => $messagerecords[$id]->fullmessagetrust
262
                ]);
263
                return $resultmessage;
264
            }, $resultmessages);
265
        }
266
 
267
        return $resultmessages;
268
    }
269
 
270
    /**
271
     * Returns description of method result value
272
     *
273
     * @return \core_external\external_description
274
     * @since Moodle 2.2
275
     */
276
    public static function send_instant_messages_returns() {
277
        return new external_multiple_structure(
278
            new external_single_structure(
279
                array(
280
                    'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds:  id of the created message if it succeeded, -1 when failed'),
281
                    'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
282
                    'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL),
283
                    'text' => new external_value(PARAM_RAW, 'The text of the message', VALUE_OPTIONAL),
284
                    'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message', VALUE_OPTIONAL),
285
                    'conversationid' => new external_value(PARAM_INT, 'The conversation id for this message', VALUE_OPTIONAL),
286
                    'useridfrom' => new external_value(PARAM_INT, 'The user id who sent the message', VALUE_OPTIONAL),
287
                    'candeletemessagesforallusers' => new external_value(PARAM_BOOL,
288
                        'If the user can delete messages in the conversation for all users', VALUE_DEFAULT, false),
289
                )
290
            )
291
        );
292
    }
293
 
294
    /**
295
     * Delete contacts parameters description.
296
     *
297
     * @return external_function_parameters
298
     * @since Moodle 2.5
299
     */
300
    public static function delete_contacts_parameters() {
301
        return new external_function_parameters(
302
            array(
303
                'userids' => new external_multiple_structure(
304
                    new external_value(PARAM_INT, 'User ID'),
305
                    'List of user IDs'
306
                ),
307
                'userid' => new external_value(PARAM_INT, 'The id of the user we are deleting the contacts for, 0 for the
308
                    current user', VALUE_DEFAULT, 0)
309
            )
310
        );
311
    }
312
 
313
    /**
314
     * Delete contacts.
315
     *
316
     * @param array $userids array of user IDs.
317
     * @param int $userid The id of the user we are deleting the contacts for
318
     * @return null
319
     * @since Moodle 2.5
320
     */
321
    public static function delete_contacts($userids, $userid = 0) {
322
        global $CFG, $USER;
323
 
324
        // Check if messaging is enabled.
325
        if (empty($CFG->messaging)) {
326
            throw new moodle_exception('disabled', 'message');
327
        }
328
 
329
        if (empty($userid)) {
330
            $userid = $USER->id;
331
        }
332
 
333
        // Validate context.
334
        $context = context_system::instance();
335
        self::validate_context($context);
336
 
337
        $params = array('userids' => $userids, 'userid' => $userid);
338
        $params = self::validate_parameters(self::delete_contacts_parameters(), $params);
339
 
340
        $capability = 'moodle/site:manageallmessaging';
341
        if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
342
            throw new required_capability_exception($context, $capability, 'nopermissions', '');
343
        }
344
 
345
        foreach ($params['userids'] as $id) {
346
            \core_message\api::remove_contact($params['userid'], $id);
347
        }
348
 
349
        return null;
350
    }
351
 
352
    /**
353
     * Delete contacts return description.
354
     *
355
     * @return \core_external\external_description
356
     * @since Moodle 2.5
357
     */
358
    public static function delete_contacts_returns() {
359
        return null;
360
    }
361
 
362
    /**
363
     * Mute conversations parameters description.
364
     *
365
     * @return external_function_parameters
366
     */
367
    public static function mute_conversations_parameters() {
368
        return new external_function_parameters(
369
            [
370
                'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
371
                'conversationids' => new external_multiple_structure(
372
                    new external_value(PARAM_INT, 'id of the conversation', VALUE_REQUIRED)
373
                ),
374
            ]
375
        );
376
    }
377
 
378
    /**
379
     * Mutes conversations.
380
     *
381
     * @param int $userid The id of the user who is blocking
382
     * @param array $conversationids The list of conversations being muted
383
     * @return \core_external\external_description
384
     */
385
    public static function mute_conversations(int $userid, array $conversationids) {
386
        global $CFG, $USER;
387
 
388
        // Check if messaging is enabled.
389
        if (empty($CFG->messaging)) {
390
            throw new moodle_exception('disabled', 'message');
391
        }
392
 
393
        // Validate context.
394
        $context = context_system::instance();
395
        self::validate_context($context);
396
 
397
        $params = ['userid' => $userid, 'conversationids' => $conversationids];
398
        $params = self::validate_parameters(self::mute_conversations_parameters(), $params);
399
 
400
        $capability = 'moodle/site:manageallmessaging';
401
        if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
402
            throw new required_capability_exception($context, $capability, 'nopermissions', '');
403
        }
404
 
405
        foreach ($params['conversationids'] as $conversationid) {
406
            if (!\core_message\api::is_conversation_muted($params['userid'], $conversationid)) {
407
                \core_message\api::mute_conversation($params['userid'], $conversationid);
408
            }
409
        }
410
 
411
        return [];
412
    }
413
 
414
    /**
415
     * Mute conversations return description.
416
     *
417
     * @return \core_external\external_description
418
     */
419
    public static function mute_conversations_returns() {
420
        return new external_warnings();
421
    }
422
 
423
    /**
424
     * Unmute conversations parameters description.
425
     *
426
     * @return external_function_parameters
427
     */
428
    public static function unmute_conversations_parameters() {
429
        return new external_function_parameters(
430
            [
431
                'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
432
                'conversationids' => new external_multiple_structure(
433
                    new external_value(PARAM_INT, 'id of the conversation', VALUE_REQUIRED)
434
                ),
435
            ]
436
        );
437
    }
438
 
439
    /**
440
     * Unmute conversations.
441
     *
442
     * @param int $userid The id of the user who is unblocking
443
     * @param array $conversationids The list of conversations being muted
444
     */
445
    public static function unmute_conversations(int $userid, array $conversationids) {
446
        global $CFG, $USER;
447
 
448
        // Check if messaging is enabled.
449
        if (empty($CFG->messaging)) {
450
            throw new moodle_exception('disabled', 'message');
451
        }
452
 
453
        // Validate context.
454
        $context = context_system::instance();
455
        self::validate_context($context);
456
 
457
        $params = ['userid' => $userid, 'conversationids' => $conversationids];
458
        $params = self::validate_parameters(self::unmute_conversations_parameters(), $params);
459
 
460
        $capability = 'moodle/site:manageallmessaging';
461
        if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
462
            throw new required_capability_exception($context, $capability, 'nopermissions', '');
463
        }
464
 
465
        foreach ($params['conversationids'] as $conversationid) {
466
            \core_message\api::unmute_conversation($params['userid'], $conversationid);
467
        }
468
 
469
        return [];
470
    }
471
 
472
    /**
473
     * Unmute conversations return description.
474
     *
475
     * @return \core_external\external_description
476
     */
477
    public static function unmute_conversations_returns() {
478
        return new external_warnings();
479
    }
480
 
481
    /**
482
     * Block user parameters description.
483
     *
484
     * @return external_function_parameters
485
     */
486
    public static function block_user_parameters() {
487
        return new external_function_parameters(
488
            [
489
                'userid' => new external_value(PARAM_INT, 'The id of the user who is blocking'),
490
                'blockeduserid' => new external_value(PARAM_INT, 'The id of the user being blocked'),
491
            ]
492
        );
493
    }
494
 
495
    /**
496
     * Blocks a user.
497
     *
498
     * @param int $userid The id of the user who is blocking
499
     * @param int $blockeduserid The id of the user being blocked
500
     * @return \core_external\external_description
501
     */
502
    public static function block_user(int $userid, int $blockeduserid) {
503
        global $CFG, $USER;
504
 
505
        // Check if messaging is enabled.
506
        if (empty($CFG->messaging)) {
507
            throw new moodle_exception('disabled', 'message');
508
        }
509
 
510
        // Validate context.
511
        $context = context_system::instance();
512
        self::validate_context($context);
513
 
514
        $params = ['userid' => $userid, 'blockeduserid' => $blockeduserid];
515
        $params = self::validate_parameters(self::block_user_parameters(), $params);
516
 
517
        $capability = 'moodle/site:manageallmessaging';
518
        if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
519
            throw new required_capability_exception($context, $capability, 'nopermissions', '');
520
        }
521
 
522
        // If the blocking is going to be useless then don't do it.
523
        if (\core_message\api::can_send_message($userid, $blockeduserid, true)) {
524
            return [];
525
        }
526
 
527
        if (!\core_message\api::is_blocked($params['userid'], $params['blockeduserid'])) {
528
            \core_message\api::block_user($params['userid'], $params['blockeduserid']);
529
        }
530
 
531
        return [];
532
    }
533
 
534
    /**
535
     * Block user return description.
536
     *
537
     * @return \core_external\external_description
538
     */
539
    public static function block_user_returns() {
540
        return new external_warnings();
541
    }
542
 
543
    /**
544
     * Unblock user parameters description.
545
     *
546
     * @return external_function_parameters
547
     */
548
    public static function unblock_user_parameters() {
549
        return new external_function_parameters(
550
            [
551
                'userid' => new external_value(PARAM_INT, 'The id of the user who is unblocking'),
552
                'unblockeduserid' => new external_value(PARAM_INT, 'The id of the user being unblocked'),
553
            ]
554
        );
555
    }
556
 
557
    /**
558
     * Unblock user.
559
     *
560
     * @param int $userid The id of the user who is unblocking
561
     * @param int $unblockeduserid The id of the user being unblocked
562
     */
563
    public static function unblock_user(int $userid, int $unblockeduserid) {
564
        global $CFG, $USER;
565
 
566
        // Check if messaging is enabled.
567
        if (empty($CFG->messaging)) {
568
            throw new moodle_exception('disabled', 'message');
569
        }
570
 
571
        // Validate context.
572
        $context = context_system::instance();
573
        self::validate_context($context);
574
 
575
        $params = ['userid' => $userid, 'unblockeduserid' => $unblockeduserid];
576
        $params = self::validate_parameters(self::unblock_user_parameters(), $params);
577
 
578
        $capability = 'moodle/site:manageallmessaging';
579
        if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
580
            throw new required_capability_exception($context, $capability, 'nopermissions', '');
581
        }
582
 
583
        \core_message\api::unblock_user($params['userid'], $params['unblockeduserid']);
584
 
585
        return [];
586
    }
587
 
588
    /**
589
     * Unblock user return description.
590
     *
591
     * @return \core_external\external_description
592
     */
593
    public static function unblock_user_returns() {
594
        return new external_warnings();
595
    }
596
 
597
    /**
598
     * Returns contact requests parameters description.
599
     *
600
     * @return external_function_parameters
601
     */
602
    public static function get_contact_requests_parameters() {
603
        return new external_function_parameters(
604
            [
605
                'userid' => new external_value(PARAM_INT, 'The id of the user we want the requests for'),
606
                'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
607
                'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
608
            ]
609
        );
610
    }
611
 
612
    /**
613
     * Handles returning the contact requests for a user.
614
     *
615
     * This also includes the user data necessary to display information
616
     * about the user.
617
     *
618
     * It will not include blocked users.
619
     *
620
     * @param int $userid The id of the user we want to get the contact requests for
621
     * @param int $limitfrom
622
     * @param int $limitnum
623
     */
624
    public static function get_contact_requests(int $userid, int $limitfrom = 0, int $limitnum = 0) {
625
        global $CFG, $USER;
626
 
627
        // Check if messaging is enabled.
628
        if (empty($CFG->messaging)) {
629
            throw new moodle_exception('disabled', 'message');
630
        }
631
 
632
        // Validate context.
633
        $context = context_system::instance();
634
        self::validate_context($context);
635
 
636
        $params = [
637
            'userid' => $userid,
638
            'limitfrom' => $limitfrom,
639
            'limitnum' => $limitnum
640
        ];
641
        $params = self::validate_parameters(self::get_contact_requests_parameters(), $params);
642
 
643
        $capability = 'moodle/site:manageallmessaging';
644
        if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
645
            throw new required_capability_exception($context, $capability, 'nopermissions', '');
646
        }
647
 
648
        return \core_message\api::get_contact_requests($params['userid'], $params['limitfrom'], $params['limitnum']);
649
    }
650
 
651
    /**
652
     * Returns the contact requests return description.
653
     *
654
     * @return \core_external\external_description
655
     */
656
    public static function get_contact_requests_returns() {
657
        return new external_multiple_structure(
658
            self::get_conversation_member_structure()
659
        );
660
    }
661
 
662
    /**
663
     * Returns the number of contact requests the user has received parameters description.
664
     *
665
     * @return external_function_parameters
666
     */
667
    public static function get_received_contact_requests_count_parameters() {
668
        return new external_function_parameters(
669
            array(
670
                'userid' => new external_value(PARAM_INT, 'The id of the user we want to return the number of ' .
671
                    'received contact requests for', VALUE_REQUIRED),
672
            )
673
        );
674
    }
675
 
676
    /**
677
     * Returns the number of contact requests the user has received.
678
     *
679
     * @param int $userid The ID of the user we want to return the number of received contact requests for
680
     * @return external_value
681
     */
682
    public static function get_received_contact_requests_count(int $userid) {
683
        global $CFG, $USER;
684
 
685
        // Check if messaging is enabled.
686
        if (empty($CFG->messaging)) {
687
            throw new moodle_exception('disabled', 'message');
688
        }
689
 
690
        // Validate context.
691
        $context = context_system::instance();
692
        self::validate_context($context);
693
 
694
        $params = [
695
            'userid' => $userid,
696
        ];
697
        $params = self::validate_parameters(self::get_received_contact_requests_count_parameters(), $params);
698
 
699
        $capability = 'moodle/site:manageallmessaging';
700
        if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
701
            throw new required_capability_exception($context, $capability, 'nopermissions', '');
702
        }
703
 
704
        return \core_message\api::get_received_contact_requests_count($params['userid']);
705
    }
706
 
707
    /**
708
     * Returns the number of contact requests the user has received return description.
709
     *
710
     * @return external_value
711
     */
712
    public static function get_received_contact_requests_count_returns() {
713
        return new external_value(PARAM_INT, 'The number of received contact requests');
714
    }
715
 
716
    /**
717
     * Returns get conversation members parameters description.
718
     *
719
     * @return external_function_parameters
720
     */
721
    public static function get_conversation_members_parameters() {
722
        return new external_function_parameters(
723
            [
724
                'userid' => new external_value(PARAM_INT, 'The id of the user we are performing this action on behalf of'),
725
                'conversationid' => new external_value(PARAM_INT, 'The id of the conversation'),
726
                'includecontactrequests' => new external_value(PARAM_BOOL, 'Do we want to include contact requests?',
727
                    VALUE_DEFAULT, false),
728
                'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Do we want to include privacy info?',
729
                    VALUE_DEFAULT, false),
730
                'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
731
                'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
732
            ]
733
        );
734
    }
735
 
736
    /**
737
     * Returns a list of conversation members.
738
     *
739
     * @param int $userid The user we are returning the conversation members for, used by helper::get_member_info.
740
     * @param int $conversationid The id of the conversation
741
     * @param bool $includecontactrequests Do we want to include contact requests with this data?
742
     * @param bool $includeprivacyinfo Do we want to include privacy info?
743
     * @param int $limitfrom
744
     * @param int $limitnum
745
     * @return array
746
     */
747
    public static function get_conversation_members(int $userid, int $conversationid, bool $includecontactrequests = false,
748
                                                    bool $includeprivacyinfo = false, int $limitfrom = 0, int $limitnum = 0) {
749
        global $CFG, $USER;
750
 
751
        // Check if messaging is enabled.
752
        if (empty($CFG->messaging)) {
753
            throw new moodle_exception('disabled', 'message');
754
        }
755
 
756
        // Validate context.
757
        $context = context_system::instance();
758
        self::validate_context($context);
759
 
760
        $params = [
761
            'userid' => $userid,
762
            'conversationid' => $conversationid,
763
            'includecontactrequests' => $includecontactrequests,
764
            'includeprivacyinfo' => $includeprivacyinfo,
765
            'limitfrom' => $limitfrom,
766
            'limitnum' => $limitnum
767
        ];
768
        $params = self::validate_parameters(self::get_conversation_members_parameters(), $params);
769
 
770
        $capability = 'moodle/site:manageallmessaging';
771
        if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
772
            throw new required_capability_exception($context, $capability, 'nopermissions', '');
773
        }
774
 
775
        // The user needs to be a part of the conversation before querying who the members are.
776
        if (!\core_message\api::is_user_in_conversation($params['userid'], $params['conversationid'])) {
777
            throw new moodle_exception('You are not a member of this conversation.');
778
        }
779
 
780
        return \core_message\api::get_conversation_members($params['userid'], $params['conversationid'], $params['includecontactrequests'],
781
            $params['includeprivacyinfo'], $params['limitfrom'], $params['limitnum']);
782
    }
783
 
784
    /**
785
     * Returns the get conversation members return description.
786
     *
787
     * @return \core_external\external_description
788
     */
789
    public static function get_conversation_members_returns() {
790
        return new external_multiple_structure(
791
            self::get_conversation_member_structure()
792
        );
793
    }
794
 
795
    /**
796
     * Creates a contact request parameters description.
797
     *
798
     * @return external_function_parameters
799
     */
800
    public static function create_contact_request_parameters() {
801
        return new external_function_parameters(
802
            [
803
                'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
804
                'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
805
            ]
806
        );
807
    }
808
 
809
    /**
810
     * Creates a contact request.
811
     *
812
     * @param int $userid The id of the user who is creating the contact request
813
     * @param int $requesteduserid The id of the user being requested
814
     */
815
    public static function create_contact_request(int $userid, int $requesteduserid) {
816
        global $CFG, $USER;
817
 
818
        // Check if messaging is enabled.
819
        if (empty($CFG->messaging)) {
820
            throw new moodle_exception('disabled', 'message');
821
        }
822
 
823
        // Validate context.
824
        $context = context_system::instance();
825
        self::validate_context($context);
826
 
827
        $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
828
        $params = self::validate_parameters(self::create_contact_request_parameters(), $params);
829
 
830
        $capability = 'moodle/site:manageallmessaging';
831
        if (($USER->id != $params['userid']) && !has_capability($capability, $context)) {
832
            throw new required_capability_exception($context, $capability, 'nopermissions', '');
833
        }
834
 
835
        $result = [
836
            'warnings' => []
837
        ];
838
 
839
        if (!\core_message\api::can_create_contact($params['userid'], $params['requesteduserid'])) {
840
            $result['warnings'][] = [
841
                'item' => 'user',
842
                'itemid' => $params['requesteduserid'],
843
                'warningcode' => 'cannotcreatecontactrequest',
844
                'message' => 'You are unable to create a contact request for this user'
845
            ];
846
        } else {
847
            if ($requests = \core_message\api::get_contact_requests_between_users($params['userid'], $params['requesteduserid'])) {
848
                // There should only ever be one but just in case there are multiple then we can return the first.
849
                $result['request'] = array_shift($requests);
850
            } else {
851
                $result['request'] = \core_message\api::create_contact_request($params['userid'], $params['requesteduserid']);
852
            }
853
        }
854
 
855
        return $result;
856
    }
857
 
858
    /**
859
     * Creates a contact request return description.
860
     *
861
     * @return \core_external\external_description
862
     */
863
    public static function create_contact_request_returns() {
864
        return new external_single_structure(
865
            array(
866
                'request' => new external_single_structure(
867
                    array(
868
                        'id' => new external_value(PARAM_INT, 'Message id'),
869
                        'userid' => new external_value(PARAM_INT, 'User from id'),
870
                        'requesteduserid' => new external_value(PARAM_INT, 'User to id'),
871
                        'timecreated' => new external_value(PARAM_INT, 'Time created'),
872
                    ),
873
                    'request record',
874
                    VALUE_OPTIONAL
875
                ),
876
                'warnings' => new external_warnings()
877
            )
878
        );
879
    }
880
 
881
    /**
882
     * Confirm a contact request parameters description.
883
     *
884
     * @return external_function_parameters
885
     */
886
    public static function confirm_contact_request_parameters() {
887
        return new external_function_parameters(
888
            [
889
                'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
890
                'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
891
            ]
892
        );
893
    }
894
 
895
    /**
896
     * Confirm a contact request.
897
     *
898
     * @param int $userid The id of the user who is creating the contact request
899
     * @param int $requesteduserid The id of the user being requested
900
     */
901
    public static function confirm_contact_request(int $userid, int $requesteduserid) {
902
        global $CFG, $USER;
903
 
904
        // Check if messaging is enabled.
905
        if (empty($CFG->messaging)) {
906
            throw new moodle_exception('disabled', 'message');
907
        }
908
 
909
        // Validate context.
910
        $context = context_system::instance();
911
        self::validate_context($context);
912
 
913
        $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
914
        $params = self::validate_parameters(self::confirm_contact_request_parameters(), $params);
915
 
916
        $capability = 'moodle/site:manageallmessaging';
917
        if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
918
            throw new required_capability_exception($context, $capability, 'nopermissions', '');
919
        }
920
 
921
        \core_message\api::confirm_contact_request($params['userid'], $params['requesteduserid']);
922
 
923
        return [];
924
    }
925
 
926
    /**
927
     * Confirm a contact request return description.
928
     *
929
     * @return \core_external\external_description
930
     */
931
    public static function confirm_contact_request_returns() {
932
        return new external_warnings();
933
    }
934
 
935
    /**
936
     * Declines a contact request parameters description.
937
     *
938
     * @return external_function_parameters
939
     */
940
    public static function decline_contact_request_parameters() {
941
        return new external_function_parameters(
942
            [
943
                'userid' => new external_value(PARAM_INT, 'The id of the user making the request'),
944
                'requesteduserid' => new external_value(PARAM_INT, 'The id of the user being requested')
945
            ]
946
        );
947
    }
948
 
949
    /**
950
     * Declines a contact request.
951
     *
952
     * @param int $userid The id of the user who is creating the contact request
953
     * @param int $requesteduserid The id of the user being requested
954
     */
955
    public static function decline_contact_request(int $userid, int $requesteduserid) {
956
        global $CFG, $USER;
957
 
958
        // Check if messaging is enabled.
959
        if (empty($CFG->messaging)) {
960
            throw new moodle_exception('disabled', 'message');
961
        }
962
 
963
        // Validate context.
964
        $context = context_system::instance();
965
        self::validate_context($context);
966
 
967
        $params = ['userid' => $userid, 'requesteduserid' => $requesteduserid];
968
        $params = self::validate_parameters(self::decline_contact_request_parameters(), $params);
969
 
970
        $capability = 'moodle/site:manageallmessaging';
971
        if (($USER->id != $params['requesteduserid']) && !has_capability($capability, $context)) {
972
            throw new required_capability_exception($context, $capability, 'nopermissions', '');
973
        }
974
 
975
        \core_message\api::decline_contact_request($params['userid'], $params['requesteduserid']);
976
 
977
        return [];
978
    }
979
 
980
    /**
981
     * Declines a contact request return description.
982
     *
983
     * @return \core_external\external_description
984
     */
985
    public static function decline_contact_request_returns() {
986
        return new external_warnings();
987
    }
988
 
989
    /**
990
     * Return the structure of a message area contact.
991
     *
992
     * @return external_single_structure
993
     * @since Moodle 3.2
994
     */
995
    private static function get_messagearea_contact_structure() {
996
        return new external_single_structure(
997
            array(
998
                'userid' => new external_value(PARAM_INT, 'The user\'s id'),
999
                'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1000
                'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1001
                'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1002
                'ismessaging' => new external_value(PARAM_BOOL, 'If we are messaging the user'),
1003
                'sentfromcurrentuser' => new external_value(PARAM_BOOL, 'Was the last message sent from the current user?'),
1004
                'lastmessage' => new external_value(PARAM_NOTAGS, 'The user\'s last message'),
1005
                'lastmessagedate' => new external_value(PARAM_INT, 'Timestamp for last message', VALUE_DEFAULT, null),
1006
                'messageid' => new external_value(PARAM_INT, 'The unique search message id', VALUE_DEFAULT, null),
1007
                'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1008
                'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1009
                'isread' => new external_value(PARAM_BOOL, 'If the user has read the message'),
1010
                'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1011
                'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1012
                    VALUE_DEFAULT, null),
1013
                'conversationid' => new external_value(PARAM_INT, 'The id of the conversation', VALUE_DEFAULT, null),
1014
            )
1015
        );
1016
    }
1017
 
1018
    /**
1019
     * Return the structure of a conversation.
1020
     *
1021
     * @return external_single_structure
1022
     * @since Moodle 3.6
1023
     */
1024
    private static function get_conversation_structure() {
1025
        return new external_single_structure(
1026
            array(
1027
                'id' => new external_value(PARAM_INT, 'The conversation id'),
1028
                'name' => new external_value(PARAM_RAW, 'The conversation name, if set', VALUE_DEFAULT, null),
1029
                'subname' => new external_value(PARAM_RAW, 'A subtitle for the conversation name, if set', VALUE_DEFAULT, null),
1030
                'imageurl' => new external_value(PARAM_URL, 'A link to the conversation picture, if set', VALUE_DEFAULT, null),
1031
                'type' => new external_value(PARAM_INT, 'The type of the conversation (1=individual,2=group,3=self)'),
1032
                'membercount' => new external_value(PARAM_INT, 'Total number of conversation members'),
1033
                'ismuted' => new external_value(PARAM_BOOL, 'If the user muted this conversation'),
1034
                'isfavourite' => new external_value(PARAM_BOOL, 'If the user marked this conversation as a favourite'),
1035
                'isread' => new external_value(PARAM_BOOL, 'If the user has read all messages in the conversation'),
1036
                'unreadcount' => new external_value(PARAM_INT, 'The number of unread messages in this conversation',
1037
                    VALUE_DEFAULT, null),
1038
                'members' => new external_multiple_structure(
1039
                    self::get_conversation_member_structure()
1040
                ),
1041
                'messages' => new external_multiple_structure(
1042
                    self::get_conversation_message_structure()
1043
                ),
1044
                'candeletemessagesforallusers' => new external_value(PARAM_BOOL,
1045
                    'If the user can delete messages in the conversation for all users', VALUE_DEFAULT, false),
1046
            )
1047
        );
1048
    }
1049
 
1050
    /**
1051
     * Return the structure of a conversation member.
1052
     *
1053
     * @return external_single_structure
1054
     * @since Moodle 3.6
1055
     */
1056
    private static function get_conversation_member_structure() {
1057
        $result = [
1058
            'id' => new external_value(PARAM_INT, 'The user id'),
1059
            'fullname' => new external_value(PARAM_NOTAGS, 'The user\'s name'),
1060
            'profileurl' => new external_value(PARAM_URL, 'The link to the user\'s profile page'),
1061
            'profileimageurl' => new external_value(PARAM_URL, 'User picture URL'),
1062
            'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL'),
1063
            'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
1064
            'showonlinestatus' => new external_value(PARAM_BOOL, 'Show the user\'s online status?'),
1065
            'isblocked' => new external_value(PARAM_BOOL, 'If the user has been blocked'),
1066
            'iscontact' => new external_value(PARAM_BOOL, 'Is the user a contact?'),
1067
            'isdeleted' => new external_value(PARAM_BOOL, 'Is the user deleted?'),
1068
            'canmessageevenifblocked' => new external_value(PARAM_BOOL,
1069
                'If the user can still message even if they get blocked'),
1070
            'canmessage' => new external_value(PARAM_BOOL, 'If the user can be messaged'),
1071
            'requirescontact' => new external_value(PARAM_BOOL, 'If the user requires to be contacts'),
1072
        ];
1073
 
1074
        $result['contactrequests'] = new external_multiple_structure(
1075
            new external_single_structure(
1076
                [
1077
                    'id' => new external_value(PARAM_INT, 'The id of the contact request'),
1078
                    'userid' => new external_value(PARAM_INT, 'The id of the user who created the contact request'),
1079
                    'requesteduserid' => new external_value(PARAM_INT, 'The id of the user confirming the request'),
1080
                    'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the contact request'),
1081
                ]
1082
            ), 'The contact requests', VALUE_OPTIONAL
1083
        );
1084
 
1085
        $result['conversations'] = new external_multiple_structure(new external_single_structure(
1086
            array(
1087
                'id' => new external_value(PARAM_INT, 'Conversations id'),
1088
                'type' => new external_value(PARAM_INT, 'Conversation type: private or public'),
1089
                'name' => new external_value(PARAM_RAW, 'Multilang compatible conversation name'. VALUE_OPTIONAL),
1090
                'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the conversation'),
1091
            ), 'information about conversation', VALUE_OPTIONAL),
1092
            'Conversations between users', VALUE_OPTIONAL
1093
        );
1094
 
1095
        return new external_single_structure(
1096
            $result
1097
        );
1098
    }
1099
 
1100
    /**
1101
     * Return the structure of a message area message.
1102
     *
1103
     * @return external_single_structure
1104
     * @since Moodle 3.6
1105
     */
1106
    private static function get_conversation_message_structure() {
1107
        return new external_single_structure(
1108
            array(
1109
                'id' => new external_value(PARAM_INT, 'The id of the message'),
1110
                'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1111
                'text' => new external_value(PARAM_RAW, 'The text of the message'),
1112
                'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1113
            )
1114
        );
1115
    }
1116
 
1117
    /**
1118
     * Get messagearea message search users parameters.
1119
     *
1120
     * @return external_function_parameters
1121
     * @since 3.6
1122
     */
1123
    public static function message_search_users_parameters() {
1124
        return new external_function_parameters(
1125
            array(
1126
                'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1127
                'search' => new external_value(PARAM_RAW, 'The string being searched'),
1128
                'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1129
                'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1130
            )
1131
        );
1132
    }
1133
 
1134
    /**
1135
     * Get search users results.
1136
     *
1137
     * @param int $userid The id of the user who is performing the search
1138
     * @param string $search The string being searched
1139
     * @param int $limitfrom
1140
     * @param int $limitnum
1141
     * @return array
1142
     * @throws moodle_exception
1143
     * @since 3.6
1144
     */
1145
    public static function message_search_users($userid, $search, $limitfrom = 0, $limitnum = 0) {
1146
        global $USER;
1147
 
1148
        $systemcontext = context_system::instance();
1149
 
1150
        $params = array(
1151
            'userid' => $userid,
1152
            'search' => $search,
1153
            'limitfrom' => $limitfrom,
1154
            'limitnum' => $limitnum
1155
        );
1156
        $params = self::validate_parameters(self::message_search_users_parameters(), $params);
1157
        self::validate_context($systemcontext);
1158
 
1159
        if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1160
            throw new moodle_exception('You do not have permission to perform this action.');
1161
        }
1162
 
1163
        list($contacts, $noncontacts) = \core_message\api::message_search_users(
1164
            $params['userid'],
1165
            $params['search'],
1166
            $params['limitfrom'],
1167
            $params['limitnum']);
1168
 
1169
        return array('contacts' => $contacts, 'noncontacts' => $noncontacts);
1170
    }
1171
 
1172
    /**
1173
     * Get messagearea message search users returns.
1174
     *
1175
     * @return external_single_structure
1176
     * @since 3.2
1177
     */
1178
    public static function message_search_users_returns() {
1179
        return new external_single_structure(
1180
            array(
1181
                'contacts' => new external_multiple_structure(
1182
                    self::get_conversation_member_structure()
1183
                ),
1184
                'noncontacts' => new external_multiple_structure(
1185
                    self::get_conversation_member_structure()
1186
                )
1187
            )
1188
        );
1189
    }
1190
 
1191
    /**
1192
     * Get messagearea search messages parameters.
1193
     *
1194
     * @return external_function_parameters
1195
     * @since 3.2
1196
     */
1197
    public static function data_for_messagearea_search_messages_parameters() {
1198
        return new external_function_parameters(
1199
            array(
1200
                'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1201
                'search' => new external_value(PARAM_RAW, 'The string being searched'),
1202
                'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1203
                'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1204
            )
1205
        );
1206
    }
1207
 
1208
    /**
1209
     * Get messagearea search messages results.
1210
     *
1211
     * @param int $userid The id of the user who is performing the search
1212
     * @param string $search The string being searched
1213
     * @param int $limitfrom
1214
     * @param int $limitnum
1215
     * @return stdClass
1216
     * @throws moodle_exception
1217
     * @since 3.2
1218
     */
1219
    public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1220
        global $CFG, $USER;
1221
 
1222
        // Check if messaging is enabled.
1223
        if (empty($CFG->messaging)) {
1224
            throw new moodle_exception('disabled', 'message');
1225
        }
1226
 
1227
        $systemcontext = context_system::instance();
1228
 
1229
        $params = array(
1230
            'userid' => $userid,
1231
            'search' => $search,
1232
            'limitfrom' => $limitfrom,
1233
            'limitnum' => $limitnum
1234
 
1235
        );
1236
        $params = self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1237
        self::validate_context($systemcontext);
1238
 
1239
        if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1240
            throw new moodle_exception('You do not have permission to perform this action.');
1241
        }
1242
 
1243
        $messages = \core_message\api::search_messages(
1244
            $params['userid'],
1245
            $params['search'],
1246
            $params['limitfrom'],
1247
            $params['limitnum']
1248
        );
1249
 
1250
        $data = new \stdClass();
1251
        $data->contacts = [];
1252
        foreach ($messages as $message) {
1253
            $contact = new \stdClass();
1254
            $contact->userid = $message->userid;
1255
            $contact->fullname = $message->fullname;
1256
            $contact->profileimageurl = $message->profileimageurl;
1257
            $contact->profileimageurlsmall = $message->profileimageurlsmall;
1258
            $contact->messageid = $message->messageid;
1259
            $contact->ismessaging = $message->ismessaging;
1260
            $contact->sentfromcurrentuser = false;
1261
            if ($message->lastmessage) {
1262
                if ($message->userid !== $message->useridfrom) {
1263
                    $contact->sentfromcurrentuser = true;
1264
                }
1265
                $contact->lastmessage = shorten_text($message->lastmessage, 60);
1266
            } else {
1267
                $contact->lastmessage = null;
1268
            }
1269
            $contact->lastmessagedate = $message->lastmessagedate;
1270
            $contact->showonlinestatus = is_null($message->isonline) ? false : true;
1271
            $contact->isonline = $message->isonline;
1272
            $contact->isblocked = $message->isblocked;
1273
            $contact->isread = $message->isread;
1274
            $contact->unreadcount = $message->unreadcount;
1275
            $contact->conversationid = $message->conversationid;
1276
 
1277
            $data->contacts[] = $contact;
1278
        }
1279
 
1280
        return $data;
1281
    }
1282
 
1283
    /**
1284
     * Get messagearea search messages returns.
1285
     *
1286
     * @return external_single_structure
1287
     * @since 3.2
1288
     */
1289
    public static function data_for_messagearea_search_messages_returns() {
1290
        return new external_single_structure(
1291
            array(
1292
                'contacts' => new external_multiple_structure(
1293
                    self::get_messagearea_contact_structure()
1294
                )
1295
            )
1296
        );
1297
    }
1298
 
1299
    /**
1300
     * Get conversations parameters.
1301
     *
1302
     * @return external_function_parameters
1303
     * @since 3.6
1304
     */
1305
    public static function get_conversations_parameters() {
1306
        return new external_function_parameters(
1307
            array(
1308
                'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1309
                'limitfrom' => new external_value(PARAM_INT, 'The offset to start at', VALUE_DEFAULT, 0),
1310
                'limitnum' => new external_value(PARAM_INT, 'Limit number of conversations to this', VALUE_DEFAULT, 0),
1311
                'type' => new external_value(PARAM_INT, 'Filter by type', VALUE_DEFAULT, null),
1312
                'favourites' => new external_value(PARAM_BOOL, 'Whether to restrict the results to contain NO favourite
1313
                conversations (false), ONLY favourite conversation (true), or ignore any restriction altogether (null)',
1314
                    VALUE_DEFAULT, null),
1315
                'mergeself' => new external_value(PARAM_BOOL, 'Whether to include self-conversations (true) or ONLY private
1316
                    conversations (false) when private conversations are requested.',
1317
                    VALUE_DEFAULT, false),
1318
            )
1319
        );
1320
    }
1321
 
1322
    /**
1323
     * Get the list of conversations for the user.
1324
     *
1325
     * @param int $userid The id of the user who is performing the search
1326
     * @param int $limitfrom
1327
     * @param int $limitnum
1328
     * @param int|null $type
1329
     * @param bool|null $favourites
1330
     * @param bool $mergeself whether to include self-conversations (true) or ONLY private conversations (false)
1331
     *             when private conversations are requested.
1332
     * @return stdClass
1333
     * @throws \moodle_exception if the messaging feature is disabled on the site.
1334
     * @since 3.2
1335
     */
1336
    public static function get_conversations($userid, $limitfrom = 0, $limitnum = 0, int $type = null, bool $favourites = null,
1337
            bool $mergeself = false) {
1338
        global $CFG, $USER;
1339
 
1340
        // All the standard BL checks.
1341
        if (empty($CFG->messaging)) {
1342
            throw new moodle_exception('disabled', 'message');
1343
        }
1344
 
1345
        $params = array(
1346
            'userid' => $userid,
1347
            'limitfrom' => $limitfrom,
1348
            'limitnum' => $limitnum,
1349
            'type' => $type,
1350
            'favourites' => $favourites,
1351
            'mergeself' => $mergeself
1352
        );
1353
        $params = self::validate_parameters(self::get_conversations_parameters(), $params);
1354
 
1355
        $systemcontext = context_system::instance();
1356
        self::validate_context($systemcontext);
1357
 
1358
        if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1359
            throw new moodle_exception('You do not have permission to perform this action.');
1360
        }
1361
 
1362
        $conversations = \core_message\api::get_conversations(
1363
            $params['userid'],
1364
            $params['limitfrom'],
1365
            $params['limitnum'],
1366
            $params['type'],
1367
            $params['favourites'],
1368
            $params['mergeself']
1369
        );
1370
 
1371
        return (object) ['conversations' => $conversations];
1372
    }
1373
 
1374
    /**
1375
     * Get conversations returns.
1376
     *
1377
     * @return external_single_structure
1378
     * @since 3.6
1379
     */
1380
    public static function get_conversations_returns() {
1381
        return new external_single_structure(
1382
            [
1383
                'conversations' => new external_multiple_structure(
1384
                    self::get_conversation_structure(true)
1385
                )
1386
            ]
1387
        );
1388
    }
1389
 
1390
    /**
1391
     * Get conversation parameters.
1392
     *
1393
     * @return external_function_parameters
1394
     */
1395
    public static function get_conversation_parameters() {
1396
        return new external_function_parameters(
1397
            array(
1398
                'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1399
                'conversationid' => new external_value(PARAM_INT, 'The id of the conversation to fetch'),
1400
                'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1401
                'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1402
                'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1403
                'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1404
                'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1405
                'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1406
                'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1407
            )
1408
        );
1409
    }
1410
 
1411
    /**
1412
     * Get a single conversation.
1413
     *
1414
     * @param int $userid The user id to get the conversation for
1415
     * @param int $conversationid The id of the conversation to fetch
1416
     * @param bool $includecontactrequests Should contact requests be included between members
1417
     * @param bool $includeprivacyinfo Should privacy info be included between members
1418
     * @param int $memberlimit Limit number of members to load
1419
     * @param int $memberoffset Offset members by this amount
1420
     * @param int $messagelimit Limit number of messages to load
1421
     * @param int $messageoffset Offset the messages
1422
     * @param bool $newestmessagesfirst Order messages by newest first
1423
     * @return stdClass
1424
     * @throws \moodle_exception if the messaging feature is disabled on the site.
1425
     */
1426
    public static function get_conversation(
1427
        int $userid,
1428
        int $conversationid,
1429
        bool $includecontactrequests = false,
1430
        bool $includeprivacyinfo = false,
1431
        int $memberlimit = 0,
1432
        int $memberoffset = 0,
1433
        int $messagelimit = 0,
1434
        int $messageoffset = 0,
1435
        bool $newestmessagesfirst = true
1436
    ) {
1437
        global $CFG, $DB, $USER;
1438
 
1439
        // All the standard BL checks.
1440
        if (empty($CFG->messaging)) {
1441
            throw new moodle_exception('disabled', 'message');
1442
        }
1443
 
1444
        $params = [
1445
            'userid' => $userid,
1446
            'conversationid' => $conversationid,
1447
            'includecontactrequests' => $includecontactrequests,
1448
            'includeprivacyinfo' => $includeprivacyinfo,
1449
            'memberlimit' => $memberlimit,
1450
            'memberoffset' => $memberoffset,
1451
            'messagelimit' => $messagelimit,
1452
            'messageoffset' => $messageoffset,
1453
            'newestmessagesfirst' => $newestmessagesfirst
1454
        ];
1455
        self::validate_parameters(self::get_conversation_parameters(), $params);
1456
 
1457
        $systemcontext = context_system::instance();
1458
        self::validate_context($systemcontext);
1459
 
1460
        $conversation = \core_message\api::get_conversation(
1461
            $params['userid'],
1462
            $params['conversationid'],
1463
            $params['includecontactrequests'],
1464
            $params['includeprivacyinfo'],
1465
            $params['memberlimit'],
1466
            $params['memberoffset'],
1467
            $params['messagelimit'],
1468
            $params['messageoffset'],
1469
            $params['newestmessagesfirst']
1470
        );
1471
 
1472
        if ($conversation) {
1473
            return $conversation;
1474
        } else {
1475
            // We have to throw an exception here because the external functions annoyingly
1476
            // don't accept null to be returned for a single structure.
1477
            throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1478
        }
1479
    }
1480
 
1481
    /**
1482
     * Get conversation returns.
1483
     *
1484
     * @return external_single_structure
1485
     */
1486
    public static function get_conversation_returns() {
1487
        return self::get_conversation_structure();
1488
    }
1489
 
1490
    /**
1491
     * Get conversation parameters.
1492
     *
1493
     * @return external_function_parameters
1494
     */
1495
    public static function get_conversation_between_users_parameters() {
1496
        return new external_function_parameters(
1497
            array(
1498
                'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1499
                'otheruserid' => new external_value(PARAM_INT, 'The other user id'),
1500
                'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1501
                'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1502
                'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1503
                'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1504
                'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1505
                'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1506
                'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1507
            )
1508
        );
1509
    }
1510
 
1511
    /**
1512
     * Get a single conversation between users.
1513
     *
1514
     * @param int $userid The user id to get the conversation for
1515
     * @param int $otheruserid The other user id
1516
     * @param bool $includecontactrequests Should contact requests be included between members
1517
     * @param bool $includeprivacyinfo Should privacy info be included between members
1518
     * @param int $memberlimit Limit number of members to load
1519
     * @param int $memberoffset Offset members by this amount
1520
     * @param int $messagelimit Limit number of messages to load
1521
     * @param int $messageoffset Offset the messages
1522
     * @param bool $newestmessagesfirst Order messages by newest first
1523
     * @return stdClass
1524
     * @throws \moodle_exception if the messaging feature is disabled on the site.
1525
     */
1526
    public static function get_conversation_between_users(
1527
        int $userid,
1528
        int $otheruserid,
1529
        bool $includecontactrequests = false,
1530
        bool $includeprivacyinfo = false,
1531
        int $memberlimit = 0,
1532
        int $memberoffset = 0,
1533
        int $messagelimit = 0,
1534
        int $messageoffset = 0,
1535
        bool $newestmessagesfirst = true
1536
    ) {
1537
        global $CFG, $DB, $USER;
1538
 
1539
        // All the standard BL checks.
1540
        if (empty($CFG->messaging)) {
1541
            throw new moodle_exception('disabled', 'message');
1542
        }
1543
 
1544
        $params = [
1545
            'userid' => $userid,
1546
            'otheruserid' => $otheruserid,
1547
            'includecontactrequests' => $includecontactrequests,
1548
            'includeprivacyinfo' => $includeprivacyinfo,
1549
            'memberlimit' => $memberlimit,
1550
            'memberoffset' => $memberoffset,
1551
            'messagelimit' => $messagelimit,
1552
            'messageoffset' => $messageoffset,
1553
            'newestmessagesfirst' => $newestmessagesfirst
1554
        ];
1555
        self::validate_parameters(self::get_conversation_between_users_parameters(), $params);
1556
 
1557
        $systemcontext = context_system::instance();
1558
        self::validate_context($systemcontext);
1559
 
1560
        $conversationid = \core_message\api::get_conversation_between_users([$params['userid'], $params['otheruserid']]);
1561
        $conversation = null;
1562
 
1563
        if ($conversationid) {
1564
            $conversation = \core_message\api::get_conversation(
1565
                $params['userid'],
1566
                $conversationid,
1567
                $params['includecontactrequests'],
1568
                $params['includeprivacyinfo'],
1569
                $params['memberlimit'],
1570
                $params['memberoffset'],
1571
                $params['messagelimit'],
1572
                $params['messageoffset'],
1573
                $params['newestmessagesfirst']
1574
            );
1575
        }
1576
 
1577
        if ($conversation) {
1578
            return $conversation;
1579
        } else {
1580
            // We have to throw an exception here because the external functions annoyingly
1581
            // don't accept null to be returned for a single structure.
1582
            throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1583
        }
1584
    }
1585
 
1586
    /**
1587
     * Get conversation returns.
1588
     *
1589
     * @return external_single_structure
1590
     */
1591
    public static function get_conversation_between_users_returns() {
1592
        return self::get_conversation_structure(true);
1593
    }
1594
 
1595
    /**
1596
     * Get self-conversation parameters.
1597
     *
1598
     * @return external_function_parameters
1599
     */
1600
    public static function get_self_conversation_parameters() {
1601
        return new external_function_parameters(
1602
            array(
1603
                'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing self-conversations for'),
1604
                'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1605
                'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1606
                'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1607
            )
1608
        );
1609
    }
1610
 
1611
    /**
1612
     * Get a single self-conversation.
1613
     *
1614
     * @param int $userid The user id to get the self-conversation for
1615
     * @param int $messagelimit Limit number of messages to load
1616
     * @param int $messageoffset Offset the messages
1617
     * @param bool $newestmessagesfirst Order messages by newest first
1618
     * @return stdClass
1619
     * @throws \moodle_exception if the messaging feature is disabled on the site.
1620
     * @since Moodle 3.7
1621
     */
1622
    public static function get_self_conversation(
1623
        int $userid,
1624
        int $messagelimit = 0,
1625
        int $messageoffset = 0,
1626
        bool $newestmessagesfirst = true
1627
    ) {
1628
        global $CFG;
1629
 
1630
        // All the standard BL checks.
1631
        if (empty($CFG->messaging)) {
1632
            throw new moodle_exception('disabled', 'message');
1633
        }
1634
 
1635
        $params = [
1636
            'userid' => $userid,
1637
            'messagelimit' => $messagelimit,
1638
            'messageoffset' => $messageoffset,
1639
            'newestmessagesfirst' => $newestmessagesfirst
1640
        ];
1641
        self::validate_parameters(self::get_self_conversation_parameters(), $params);
1642
 
1643
        $systemcontext = context_system::instance();
1644
        self::validate_context($systemcontext);
1645
 
1646
        $conversation = \core_message\api::get_self_conversation($params['userid']);
1647
 
1648
        if ($conversation) {
1649
            $conversation = \core_message\api::get_conversation(
1650
                $params['userid'],
1651
                $conversation->id,
1652
                false,
1653
                false,
1654
                0,
1655
                0,
1656
                $params['messagelimit'],
1657
                $params['messageoffset'],
1658
                $params['newestmessagesfirst']
1659
            );
1660
        }
1661
 
1662
        if ($conversation) {
1663
            return $conversation;
1664
        } else {
1665
            // We have to throw an exception here because the external functions annoyingly
1666
            // don't accept null to be returned for a single structure.
1667
            throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1668
        }
1669
    }
1670
 
1671
    /**
1672
     * Get conversation returns.
1673
     *
1674
     * @return external_single_structure
1675
     */
1676
    public static function get_self_conversation_returns() {
1677
        return self::get_conversation_structure();
1678
    }
1679
 
1680
    /**
1681
     * The conversation messages parameters.
1682
     *
1683
     * @return external_function_parameters
1684
     * @since 3.6
1685
     */
1686
    public static function get_conversation_messages_parameters() {
1687
        return new external_function_parameters(
1688
            array(
1689
                'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1690
                'convid' => new external_value(PARAM_INT, 'The conversation id'),
1691
                'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1692
                'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1693
                'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1694
                'timefrom' => new external_value(PARAM_INT,
1695
                    'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1696
            )
1697
        );
1698
    }
1699
 
1700
    /**
1701
     * Get conversation messages.
1702
     *
1703
     * @param  int $currentuserid The current user's id.
1704
     * @param  int $convid The conversation id.
1705
     * @param  int $limitfrom Return a subset of records, starting at this point (optional).
1706
     * @param  int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
1707
     * @param  bool $newest True for getting first newest messages, false otherwise.
1708
     * @param  int  $timefrom The time from the conversation messages to get.
1709
     * @return array The messages and members who have sent some of these messages.
1710
     * @throws moodle_exception
1711
     * @since 3.6
1712
     */
1713
    public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
1714
                                                         bool $newest = false, int $timefrom = 0) {
1715
        global $CFG, $USER;
1716
 
1717
        // Check if messaging is enabled.
1718
        if (empty($CFG->messaging)) {
1719
            throw new moodle_exception('disabled', 'message');
1720
        }
1721
 
1722
        $systemcontext = context_system::instance();
1723
 
1724
        $params = array(
1725
            'currentuserid' => $currentuserid,
1726
            'convid' => $convid,
1727
            'limitfrom' => $limitfrom,
1728
            'limitnum' => $limitnum,
1729
            'newest' => $newest,
1730
            'timefrom' => $timefrom,
1731
        );
1732
        $params = self::validate_parameters(self::get_conversation_messages_parameters(), $params);
1733
        self::validate_context($systemcontext);
1734
 
1735
        if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1736
            throw new moodle_exception('You do not have permission to perform this action.');
1737
        }
1738
 
1739
        // Check that the user belongs to the conversation.
1740
        if (!\core_message\api::is_user_in_conversation($params['currentuserid'], $params['convid'])) {
1741
            throw new moodle_exception('User is not part of conversation.');
1742
        }
1743
 
1744
        $sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
1745
 
1746
        // We need to enforce a one second delay on messages to avoid race conditions of current
1747
        // messages still being sent.
1748
        //
1749
        // There is a chance that we could request messages before the current time's
1750
        // second has elapsed and while other messages are being sent in that same second. In which
1751
        // case those messages will be lost.
1752
        //
1753
        // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1754
        $timeto = empty($params['timefrom']) ? 0 : time() - 1;
1755
 
1756
        // No requesting messages from the current time, as stated above.
1757
        if ($params['timefrom'] == time()) {
1758
            $messages = [];
1759
        } else {
1760
            $messages = \core_message\api::get_conversation_messages(
1761
                $params['currentuserid'],
1762
                $params['convid'],
1763
                $params['limitfrom'],
1764
                $params['limitnum'],
1765
                $sort,
1766
                $params['timefrom'],
1767
                $timeto);
1768
        }
1769
 
1770
        return $messages;
1771
    }
1772
 
1773
    /**
1774
     * The messagearea messages return structure.
1775
     *
1776
     * @return external_single_structure
1777
     * @since 3.6
1778
     */
1779
    public static function get_conversation_messages_returns() {
1780
        return new external_single_structure(
1781
            array(
1782
                'id' => new external_value(PARAM_INT, 'The conversation id'),
1783
                'members' => new external_multiple_structure(
1784
                    self::get_conversation_member_structure()
1785
                ),
1786
                'messages' => new external_multiple_structure(
1787
                    self::get_conversation_message_structure()
1788
                ),
1789
            )
1790
        );
1791
    }
1792
 
1793
    /**
1794
     * The user contacts return parameters.
1795
     *
1796
     * @return external_function_parameters
1797
     */
1798
    public static function get_user_contacts_parameters() {
1799
        return new external_function_parameters(
1800
            array(
1801
                'userid' => new external_value(PARAM_INT, 'The id of the user who we retrieving the contacts for'),
1802
                'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1803
                'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1804
            )
1805
        );
1806
    }
1807
 
1808
    /**
1809
     * Get user contacts.
1810
     *
1811
     * @param int $userid The id of the user who we are viewing conversations for
1812
     * @param int $limitfrom
1813
     * @param int $limitnum
1814
     * @return array
1815
     * @throws moodle_exception
1816
     */
1817
    public static function get_user_contacts(int $userid, int $limitfrom = 0, int $limitnum = 0) {
1818
        global $CFG, $USER;
1819
 
1820
        // Check if messaging is enabled.
1821
        if (empty($CFG->messaging)) {
1822
            throw new moodle_exception('disabled', 'message');
1823
        }
1824
 
1825
        $systemcontext = context_system::instance();
1826
 
1827
        $params = array(
1828
            'userid' => $userid,
1829
            'limitfrom' => $limitfrom,
1830
            'limitnum' => $limitnum
1831
        );
1832
        $params = self::validate_parameters(self::get_user_contacts_parameters(), $params);
1833
        self::validate_context($systemcontext);
1834
 
1835
        if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1836
            throw new moodle_exception('You do not have permission to perform this action.');
1837
        }
1838
 
1839
        return \core_message\api::get_user_contacts($params['userid'], $params['limitfrom'], $params['limitnum']);
1840
    }
1841
 
1842
    /**
1843
     * The user contacts return structure.
1844
     *
1845
     * @return external_multiple_structure
1846
     */
1847
    public static function get_user_contacts_returns() {
1848
        return new external_multiple_structure(
1849
            self::get_conversation_member_structure()
1850
        );
1851
    }
1852
 
1853
    /**
1854
     * Search contacts parameters description.
1855
     *
1856
     * @return external_function_parameters
1857
     * @since Moodle 2.5
1858
     */
1859
    public static function search_contacts_parameters() {
1860
        return new external_function_parameters(
1861
            array(
1862
                'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
1863
                'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
1864
                    VALUE_DEFAULT, false)
1865
            )
1866
        );
1867
    }
1868
 
1869
    /**
1870
     * Search contacts.
1871
     *
1872
     * @param string $searchtext query string.
1873
     * @param bool $onlymycourses limit the search to the user's courses only.
1874
     * @return \core_external\external_description
1875
     * @since Moodle 2.5
1876
     */
1877
    public static function search_contacts($searchtext, $onlymycourses = false) {
1878
        global $CFG, $USER, $PAGE;
1879
        require_once($CFG->dirroot . '/user/lib.php');
1880
 
1881
        // Check if messaging is enabled.
1882
        if (empty($CFG->messaging)) {
1883
            throw new moodle_exception('disabled', 'message');
1884
        }
1885
 
1886
        require_once($CFG->libdir . '/enrollib.php');
1887
 
1888
        $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
1889
        $params = self::validate_parameters(self::search_contacts_parameters(), $params);
1890
 
1891
        // Extra validation, we do not allow empty queries.
1892
        if ($params['searchtext'] === '') {
1893
            throw new moodle_exception('querystringcannotbeempty');
1894
        }
1895
 
1896
        $courseids = array();
1897
        if ($params['onlymycourses']) {
1898
            $mycourses = enrol_get_my_courses(array('id'));
1899
            foreach ($mycourses as $mycourse) {
1900
                $courseids[] = $mycourse->id;
1901
            }
1902
        } else {
1903
            $courseids[] = SITEID;
1904
        }
1905
 
1906
        // Retrieving the users matching the query.
1907
        $users = message_search_users($courseids, $params['searchtext']);
1908
        $results = array();
1909
        foreach ($users as $user) {
1910
            $results[$user->id] = $user;
1911
        }
1912
 
1913
        // Reorganising information.
1914
        foreach ($results as &$user) {
1915
            $newuser = array(
1916
                'id' => $user->id,
1917
                'fullname' => fullname($user)
1918
            );
1919
 
1920
            // Avoid undefined property notice as phone not specified.
1921
            $user->phone1 = null;
1922
            $user->phone2 = null;
1923
 
1924
            $userpicture = new user_picture($user);
1925
            $userpicture->size = 1; // Size f1.
1926
            $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1927
            $userpicture->size = 0; // Size f2.
1928
            $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1929
 
1930
            $user = $newuser;
1931
        }
1932
 
1933
        return $results;
1934
    }
1935
 
1936
    /**
1937
     * Search contacts return description.
1938
     *
1939
     * @return \core_external\external_description
1940
     * @since Moodle 2.5
1941
     */
1942
    public static function search_contacts_returns() {
1943
        return new external_multiple_structure(
1944
            new external_single_structure(
1945
                array(
1946
                    'id' => new external_value(PARAM_INT, 'User ID'),
1947
                    'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1948
                    'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1949
                    'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
1950
                )
1951
            ),
1952
            'List of contacts'
1953
        );
1954
    }
1955
 
1956
    /**
1957
     * Get messages parameters description.
1958
     *
1959
     * @return external_function_parameters
1960
     * @since 2.8
1961
     */
1962
    public static function get_messages_parameters() {
1963
        return new external_function_parameters(
1964
            array(
1965
                'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
1966
                'useridfrom' => new external_value(
1967
                    PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
1968
                    VALUE_DEFAULT, 0),
1969
                'type' => new external_value(
1970
                    PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
1971
                    VALUE_DEFAULT, 'both'),
1972
                'read' => new external_value(PARAM_INT, '1 for getting read messages, 0 for unread, 2 for both',
1973
                    VALUE_DEFAULT, 1),
1974
                'newestfirst' => new external_value(
1975
                    PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
1976
                    VALUE_DEFAULT, true),
1977
                'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
1978
                'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
1979
            )
1980
        );
1981
    }
1982
 
1983
    /**
1984
     * Get messages function implementation.
1985
     *
1986
     * @since  2.8
1987
     * @throws invalid_parameter_exception
1988
     * @throws moodle_exception
1989
     * @param  int      $useridto       the user id who received the message
1990
     * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
1991
     * @param  string   $type           type of message to return, expected values: notifications, conversations and both
1992
     * @param  int      $read           1 for getting read messages, 0 for unread, 2 for both
1993
     * @param  bool     $newestfirst    true for ordering by newest first, false for oldest first
1994
     * @param  int      $limitfrom      limit from
1995
     * @param  int      $limitnum       limit num
1996
     * @return \core_external\external_description
1997
     */
1998
    public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = MESSAGE_GET_READ,
1999
                                        $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
2000
        global $CFG, $USER, $PAGE;
2001
 
2002
        $warnings = array();
2003
 
2004
        $params = array(
2005
            'useridto' => $useridto,
2006
            'useridfrom' => $useridfrom,
2007
            'type' => $type,
2008
            'read' => $read,
2009
            'newestfirst' => $newestfirst,
2010
            'limitfrom' => $limitfrom,
2011
            'limitnum' => $limitnum
2012
        );
2013
 
2014
        $params = self::validate_parameters(self::get_messages_parameters(), $params);
2015
 
2016
        $context = context_system::instance();
2017
        self::validate_context($context);
2018
 
2019
        $useridto = $params['useridto'];
2020
        $useridfrom = $params['useridfrom'];
2021
        $type = $params['type'];
2022
        $read = $params['read'];
2023
        $newestfirst = $params['newestfirst'];
2024
        $limitfrom = $params['limitfrom'];
2025
        $limitnum = $params['limitnum'];
2026
 
2027
        $allowedvalues = array('notifications', 'conversations', 'both');
2028
        if (!in_array($type, $allowedvalues)) {
2029
            throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
2030
                'allowed values are: ' . implode(',', $allowedvalues));
2031
        }
2032
 
2033
        // Check if private messaging between users is allowed.
2034
        if (empty($CFG->messaging)) {
2035
            // If we are retreiving only conversations, and messaging is disabled, throw an exception.
2036
            if ($type == "conversations") {
2037
                throw new moodle_exception('disabled', 'message');
2038
            }
2039
            if ($type == "both") {
2040
                $warning = array();
2041
                $warning['item'] = 'message';
2042
                $warning['itemid'] = $USER->id;
2043
                $warning['warningcode'] = '1';
2044
                $warning['message'] = 'Private messages (conversations) are not enabled in this site.
2045
                    Only notifications will be returned';
2046
                $warnings[] = $warning;
2047
            }
2048
        }
2049
 
2050
        if (!empty($useridto)) {
2051
            if (core_user::is_real_user($useridto)) {
2052
                $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2053
            } else {
2054
                throw new moodle_exception('invaliduser');
2055
            }
2056
        }
2057
 
2058
        if (!empty($useridfrom)) {
2059
            // We use get_user here because the from user can be the noreply or support user.
2060
            $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2061
        }
2062
 
2063
        // Check if the current user is the sender/receiver or just a privileged user.
2064
        if ($useridto != $USER->id and $useridfrom != $USER->id and
2065
             !has_capability('moodle/site:readallmessages', $context)) {
2066
            throw new moodle_exception('accessdenied', 'admin');
2067
        }
2068
 
2069
        // Which type of messages to retrieve.
2070
        $notifications = -1;
2071
        if ($type != 'both') {
2072
            $notifications = ($type == 'notifications') ? 1 : 0;
2073
        }
2074
 
2075
        $orderdirection = $newestfirst ? 'DESC' : 'ASC';
2076
        $sort = "mr.timecreated $orderdirection";
2077
 
2078
        if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
2079
            $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
2080
 
2081
            // In some cases, we don't need to get the to/from user objects from the sql query.
2082
            $userfromfullname = '';
2083
            $usertofullname = '';
2084
 
2085
            // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
2086
            if (!empty($useridto)) {
2087
                $usertofullname = fullname($userto, $canviewfullname);
2088
                // The user from may or may not be filled.
2089
                if (!empty($useridfrom)) {
2090
                    $userfromfullname = fullname($userfrom, $canviewfullname);
2091
                }
2092
            } else {
2093
                // If the useridto field is empty, the useridfrom must be filled.
2094
                $userfromfullname = fullname($userfrom, $canviewfullname);
2095
            }
2096
            foreach ($messages as $mid => $message) {
2097
 
2098
                if (!$message->notification) {
2099
                    // Do not return deleted messages.
2100
                    if (($useridto == $USER->id and $message->timeusertodeleted) or
2101
                        ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
2102
                        unset($messages[$mid]);
2103
                        continue;
2104
                    }
2105
                } else {
2106
                    // Return iconurl for notifications.
2107
                    if (!isset($output)) {
2108
                        $output = $PAGE->get_renderer('core');
2109
                    }
2110
 
2111
                    if (!empty($message->component) && substr($message->component, 0, 4) == 'mod_') {
2112
                        $iconurl = $output->image_url('monologo', $message->component);
2113
                    } else {
2114
                        $iconurl = $output->image_url('i/marker', 'core');
2115
                    }
2116
 
2117
                    $message->iconurl = clean_param($iconurl->out(), PARAM_URL);
2118
                }
2119
 
2120
                // We need to get the user from the query.
2121
                if (empty($userfromfullname)) {
2122
                    // Check for non-reply and support users.
2123
                    if (core_user::is_real_user($message->useridfrom)) {
2124
                        $user = new stdClass();
2125
                        $user = username_load_fields_from_object($user, $message, 'userfrom');
2126
                        $message->userfromfullname = fullname($user, $canviewfullname);
2127
                    } else {
2128
                        $user = core_user::get_user($message->useridfrom);
2129
                        $message->userfromfullname = fullname($user, $canviewfullname);
2130
                    }
2131
                } else {
2132
                    $message->userfromfullname = $userfromfullname;
2133
                }
2134
 
2135
                // We need to get the user from the query.
2136
                if (empty($usertofullname)) {
2137
                    $user = new stdClass();
2138
                    $user = username_load_fields_from_object($user, $message, 'userto');
2139
                    $message->usertofullname = fullname($user, $canviewfullname);
2140
                } else {
2141
                    $message->usertofullname = $usertofullname;
2142
                }
2143
 
2144
                // Clean subject of html.
2145
                $message->subject = clean_param($message->subject, PARAM_TEXT);
2146
                $message->text = message_format_message_text($message);
2147
                $messages[$mid] = (array) $message;
2148
            }
2149
        }
2150
 
2151
        $results = array(
2152
            'messages' => $messages,
2153
            'warnings' => $warnings
2154
        );
2155
 
2156
        return $results;
2157
    }
2158
 
2159
    /**
2160
     * Get messages return description.
2161
     *
2162
     * @return external_single_structure
2163
     * @since 2.8
2164
     */
2165
    public static function get_messages_returns() {
2166
        return new external_single_structure(
2167
            array(
2168
                'messages' => new external_multiple_structure(
2169
                    new external_single_structure(
2170
                        array(
2171
                            'id' => new external_value(PARAM_INT, 'Message id'),
2172
                            'useridfrom' => new external_value(PARAM_INT, 'User from id'),
2173
                            'useridto' => new external_value(PARAM_INT, 'User to id'),
2174
                            'subject' => new external_value(PARAM_TEXT, 'The message subject'),
2175
                            'text' => new external_value(PARAM_RAW, 'The message text formated'),
2176
                            'fullmessage' => new external_value(PARAM_RAW, 'The message'),
2177
                            'fullmessageformat' => new external_format_value('fullmessage'),
2178
                            'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
2179
                            'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
2180
                            'notification' => new external_value(PARAM_INT, 'Is a notification?'),
2181
                            'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
2182
                            'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
2183
                            'timecreated' => new external_value(PARAM_INT, 'Time created'),
2184
                            'timeread' => new external_value(PARAM_INT, 'Time read'),
2185
                            'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
2186
                            'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name'),
2187
                            'component' => new external_value(PARAM_TEXT, 'The component that generated the notification',
2188
                                VALUE_OPTIONAL),
2189
                            'eventtype' => new external_value(PARAM_TEXT, 'The type of notification', VALUE_OPTIONAL),
2190
                            'customdata' => new external_value(PARAM_RAW, 'Custom data to be passed to the message processor.
2191
                                The data here is serialised using json_encode().', VALUE_OPTIONAL),
2192
                            'iconurl' => new external_value(PARAM_URL, 'URL for icon, only for notifications.', VALUE_OPTIONAL),
2193
                        ), 'message'
2194
                    )
2195
                ),
2196
                'warnings' => new external_warnings()
2197
            )
2198
        );
2199
    }
2200
 
2201
    /**
2202
     * Mark all notifications as read parameters description.
2203
     *
2204
     * @return external_function_parameters
2205
     * @since 3.2
2206
     */
2207
    public static function mark_all_notifications_as_read_parameters() {
2208
        return new external_function_parameters(
2209
            array(
2210
                'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2211
                'useridfrom' => new external_value(
2212
                    PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2213
                    VALUE_DEFAULT, 0),
2214
                'timecreatedto' => new external_value(
2215
                    PARAM_INT, 'mark messages created before this time as read, 0 for all messages',
2216
                    VALUE_DEFAULT, 0),
2217
            )
2218
        );
2219
    }
2220
 
2221
    /**
2222
     * Mark all notifications as read function.
2223
     *
2224
     * @since  3.2
2225
     * @throws invalid_parameter_exception
2226
     * @throws moodle_exception
2227
     * @param  int      $useridto       the user id who received the message
2228
     * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
2229
     * @param  int      $timecreatedto  mark message created before this time as read, 0 for all messages
2230
     * @return \core_external\external_description
2231
     */
2232
    public static function mark_all_notifications_as_read($useridto, $useridfrom, $timecreatedto = 0) {
2233
        global $USER;
2234
 
2235
        $params = self::validate_parameters(
2236
            self::mark_all_notifications_as_read_parameters(),
2237
            array(
2238
                'useridto' => $useridto,
2239
                'useridfrom' => $useridfrom,
2240
                'timecreatedto' => $timecreatedto,
2241
            )
2242
        );
2243
 
2244
        $context = context_system::instance();
2245
        self::validate_context($context);
2246
 
2247
        $useridto = $params['useridto'];
2248
        $useridfrom = $params['useridfrom'];
2249
        $timecreatedto = $params['timecreatedto'];
2250
 
2251
        if (!empty($useridto)) {
2252
            if (core_user::is_real_user($useridto)) {
2253
                $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2254
            } else {
2255
                throw new moodle_exception('invaliduser');
2256
            }
2257
        }
2258
 
2259
        if (!empty($useridfrom)) {
2260
            // We use get_user here because the from user can be the noreply or support user.
2261
            $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2262
        }
2263
 
2264
        // Check if the current user is the sender/receiver or just a privileged user.
2265
        if ($useridto != $USER->id and $useridfrom != $USER->id and
2266
            // The deleteanymessage cap seems more reasonable here than readallmessages.
2267
             !has_capability('moodle/site:deleteanymessage', $context)) {
2268
            throw new moodle_exception('accessdenied', 'admin');
2269
        }
2270
 
2271
        \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom, $timecreatedto);
2272
 
2273
        return true;
2274
    }
2275
 
2276
    /**
2277
     * Mark all notifications as read return description.
2278
     *
2279
     * @return external_single_structure
2280
     * @since 3.2
2281
     */
2282
    public static function mark_all_notifications_as_read_returns() {
2283
        return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2284
    }
2285
 
2286
    /**
2287
     * Get unread conversations count parameters description.
2288
     *
2289
     * @return external_function_parameters
2290
     * @since 3.2
2291
     */
2292
    public static function get_unread_conversations_count_parameters() {
2293
        return new external_function_parameters(
2294
            array(
2295
                'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2296
            )
2297
        );
2298
    }
2299
 
2300
    /**
2301
     * Get unread messages count function.
2302
     *
2303
     * @since  3.2
2304
     * @throws invalid_parameter_exception
2305
     * @throws moodle_exception
2306
     * @param  int      $useridto       the user id who received the message
2307
     * @return \core_external\external_description
2308
     */
2309
    public static function get_unread_conversations_count($useridto) {
2310
        global $USER, $CFG;
2311
 
2312
        // Check if messaging is enabled.
2313
        if (empty($CFG->messaging)) {
2314
            throw new moodle_exception('disabled', 'message');
2315
        }
2316
 
2317
        $params = self::validate_parameters(
2318
            self::get_unread_conversations_count_parameters(),
2319
            array('useridto' => $useridto)
2320
        );
2321
 
2322
        $context = context_system::instance();
2323
        self::validate_context($context);
2324
 
2325
        $useridto = $params['useridto'];
2326
 
2327
        if (!empty($useridto)) {
2328
            if (core_user::is_real_user($useridto)) {
2329
                $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2330
            } else {
2331
                throw new moodle_exception('invaliduser');
2332
            }
2333
        } else {
2334
            $useridto = $USER->id;
2335
        }
2336
 
2337
        // Check if the current user is the receiver or just a privileged user.
2338
        if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
2339
            throw new moodle_exception('accessdenied', 'admin');
2340
        }
2341
 
2342
        return \core_message\api::count_unread_conversations($userto);
2343
    }
2344
 
2345
    /**
2346
     * Get unread conversations count return description.
2347
     *
2348
     * @return external_single_structure
2349
     * @since 3.2
2350
     */
2351
    public static function get_unread_conversations_count_returns() {
2352
        return new external_value(PARAM_INT, 'The count of unread messages for the user');
2353
    }
2354
 
2355
    /**
2356
     * Get blocked users parameters description.
2357
     *
2358
     * @return external_function_parameters
2359
     * @since 2.9
2360
     */
2361
    public static function get_blocked_users_parameters() {
2362
        return new external_function_parameters(
2363
            array(
2364
                'userid' => new external_value(PARAM_INT,
2365
                                'the user whose blocked users we want to retrieve',
2366
                                VALUE_REQUIRED),
2367
            )
2368
        );
2369
    }
2370
 
2371
    /**
2372
     * Retrieve a list of users blocked
2373
     *
2374
     * @param  int $userid the user whose blocked users we want to retrieve
2375
     * @return \core_external\external_description
2376
     * @since 2.9
2377
     */
2378
    public static function get_blocked_users($userid) {
2379
        global $CFG, $USER, $PAGE;
2380
 
2381
        // Warnings array, it can be empty at the end but is mandatory.
2382
        $warnings = array();
2383
 
2384
        // Validate params.
2385
        $params = array(
2386
            'userid' => $userid
2387
        );
2388
        $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
2389
        $userid = $params['userid'];
2390
 
2391
        // Validate context.
2392
        $context = context_system::instance();
2393
        self::validate_context($context);
2394
 
2395
        // Check if private messaging between users is allowed.
2396
        if (empty($CFG->messaging)) {
2397
            throw new moodle_exception('disabled', 'message');
2398
        }
2399
 
2400
        $user = core_user::get_user($userid, '*', MUST_EXIST);
2401
        core_user::require_active_user($user);
2402
 
2403
        // Check if we have permissions for retrieve the information.
2404
        $capability = 'moodle/site:manageallmessaging';
2405
        if (($USER->id != $userid) && !has_capability($capability, $context)) {
2406
            throw new required_capability_exception($context, $capability, 'nopermissions', '');
2407
        }
2408
 
2409
        // Now, we can get safely all the blocked users.
2410
        $users = \core_message\api::get_blocked_users($user->id);
2411
 
2412
        $blockedusers = array();
2413
        foreach ($users as $user) {
2414
            $newuser = array(
2415
                'id' => $user->id,
2416
                'fullname' => fullname($user),
2417
            );
2418
 
2419
            $userpicture = new user_picture($user);
2420
            $userpicture->size = 1; // Size f1.
2421
            $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2422
 
2423
            $blockedusers[] = $newuser;
2424
        }
2425
 
2426
        $results = array(
2427
            'users' => $blockedusers,
2428
            'warnings' => $warnings
2429
        );
2430
        return $results;
2431
    }
2432
 
2433
    /**
2434
     * Get blocked users return description.
2435
     *
2436
     * @return external_single_structure
2437
     * @since 2.9
2438
     */
2439
    public static function get_blocked_users_returns() {
2440
        return new external_single_structure(
2441
            array(
2442
                'users' => new external_multiple_structure(
2443
                    new external_single_structure(
2444
                        array(
2445
                            'id' => new external_value(PARAM_INT, 'User ID'),
2446
                            'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2447
                            'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
2448
                        )
2449
                    ),
2450
                    'List of blocked users'
2451
                ),
2452
                'warnings' => new external_warnings()
2453
            )
2454
        );
2455
    }
2456
 
2457
    /**
2458
     * Returns description of method parameters
2459
     *
2460
     * @return external_function_parameters
2461
     * @since 2.9
2462
     */
2463
    public static function mark_message_read_parameters() {
2464
        return new external_function_parameters(
2465
            array(
2466
                'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
2467
                'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
2468
                    VALUE_DEFAULT, 0)
2469
            )
2470
        );
2471
    }
2472
 
2473
    /**
2474
     * Mark a single message as read, trigger message_viewed event
2475
     *
2476
     * @param  int $messageid id of the message (in the message table)
2477
     * @param  int $timeread timestamp for when the message should be marked read
2478
     * @return \core_external\external_description
2479
     * @throws invalid_parameter_exception
2480
     * @throws moodle_exception
2481
     * @since 2.9
2482
     */
2483
    public static function mark_message_read($messageid, $timeread) {
2484
        global $CFG, $DB, $USER;
2485
 
2486
        // Check if private messaging between users is allowed.
2487
        if (empty($CFG->messaging)) {
2488
            throw new moodle_exception('disabled', 'message');
2489
        }
2490
 
2491
        // Warnings array, it can be empty at the end but is mandatory.
2492
        $warnings = array();
2493
 
2494
        // Validate params.
2495
        $params = array(
2496
            'messageid' => $messageid,
2497
            'timeread' => $timeread
2498
        );
2499
        $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
2500
 
2501
        if (empty($params['timeread'])) {
2502
            $timeread = time();
2503
        } else {
2504
            $timeread = $params['timeread'];
2505
        }
2506
 
2507
        // Validate context.
2508
        $context = context_system::instance();
2509
        self::validate_context($context);
2510
 
2511
        $sql = "SELECT m.*, mcm.userid as useridto
2512
                  FROM {messages} m
2513
            INNER JOIN {message_conversations} mc
2514
                    ON m.conversationid = mc.id
2515
            INNER JOIN {message_conversation_members} mcm
2516
                    ON mcm.conversationid = mc.id
2517
             LEFT JOIN {message_user_actions} mua
2518
                    ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
2519
                 WHERE mua.id is NULL
2520
                   AND mcm.userid != m.useridfrom
2521
                   AND m.id = ?";
2522
        $messageparams = [];
2523
        $messageparams[] = $USER->id;
2524
        $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
2525
        $messageparams[] = $params['messageid'];
2526
        $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
2527
 
2528
        if ($message->useridto != $USER->id) {
2529
            throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
2530
        }
2531
 
2532
        \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
2533
 
2534
        $results = array(
2535
            'messageid' => $message->id,
2536
            'warnings' => $warnings
2537
        );
2538
        return $results;
2539
    }
2540
 
2541
    /**
2542
     * Returns description of method result value
2543
     *
2544
     * @return \core_external\external_description
2545
     * @since 2.9
2546
     */
2547
    public static function mark_message_read_returns() {
2548
        return new external_single_structure(
2549
            array(
2550
                'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
2551
                'warnings' => new external_warnings()
2552
            )
2553
        );
2554
    }
2555
 
2556
    /**
2557
     * Returns description of method parameters
2558
     *
2559
     * @return external_function_parameters
2560
     */
2561
    public static function mark_notification_read_parameters() {
2562
        return new external_function_parameters(
2563
            array(
2564
                'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2565
                'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
2566
                    VALUE_DEFAULT, 0)
2567
            )
2568
        );
2569
    }
2570
 
2571
    /**
2572
     * Mark a single notification as read.
2573
     *
2574
     * This will trigger a 'notification_viewed' event.
2575
     *
2576
     * @param int $notificationid id of the notification
2577
     * @param int $timeread timestamp for when the notification should be marked read
2578
     * @return \core_external\external_description
2579
     * @throws invalid_parameter_exception
2580
     * @throws moodle_exception
2581
     */
2582
    public static function mark_notification_read($notificationid, $timeread) {
2583
        global $CFG, $DB, $USER;
2584
 
2585
        // Warnings array, it can be empty at the end but is mandatory.
2586
        $warnings = array();
2587
 
2588
        // Validate params.
2589
        $params = array(
2590
            'notificationid' => $notificationid,
2591
            'timeread' => $timeread
2592
        );
2593
        $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
2594
 
2595
        if (empty($params['timeread'])) {
2596
            $timeread = time();
2597
        } else {
2598
            $timeread = $params['timeread'];
2599
        }
2600
 
2601
        // Validate context.
2602
        $context = context_system::instance();
2603
        self::validate_context($context);
2604
 
2605
        $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
2606
 
2607
        if ($notification->useridto != $USER->id) {
2608
            throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
2609
                'notification as read');
2610
        }
2611
 
2612
        \core_message\api::mark_notification_as_read($notification, $timeread);
2613
 
2614
        $results = array(
2615
            'notificationid' => $notification->id,
2616
            'warnings' => $warnings
2617
        );
2618
 
2619
        return $results;
2620
    }
2621
 
2622
    /**
2623
     * Returns description of method result value
2624
     *
2625
     * @return \core_external\external_description
2626
     */
2627
    public static function mark_notification_read_returns() {
2628
        return new external_single_structure(
2629
            array(
2630
                'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2631
                'warnings' => new external_warnings()
2632
            )
2633
        );
2634
    }
2635
 
2636
    /**
2637
     * Mark all conversation messages as read parameters description.
2638
     *
2639
     * @return external_function_parameters
2640
     * @since 3.6
2641
     */
2642
    public static function mark_all_conversation_messages_as_read_parameters() {
2643
        return new external_function_parameters(
2644
            array(
2645
                'userid' => new external_value(PARAM_INT, 'The user id who who we are marking the messages as read for'),
2646
                'conversationid' =>
2647
                    new external_value(PARAM_INT, 'The conversation id who who we are marking the messages as read for')
2648
            )
2649
        );
2650
    }
2651
 
2652
    /**
2653
     * Mark all conversation messages as read function.
2654
     *
2655
     * @param int $userid The user id of who we want to delete the conversation for
2656
     * @param int $conversationid The id of the conversations
2657
     * @since 3.6
2658
     */
2659
    public static function mark_all_conversation_messages_as_read(int $userid, int $conversationid) {
2660
        global $CFG;
2661
 
2662
        // Check if messaging is enabled.
2663
        if (empty($CFG->messaging)) {
2664
            throw new moodle_exception('disabled', 'message');
2665
        }
2666
 
2667
        $params = array(
2668
            'userid' => $userid,
2669
            'conversationid' => $conversationid,
2670
        );
2671
        $params = self::validate_parameters(self::mark_all_conversation_messages_as_read_parameters(), $params);
2672
 
2673
        $context = context_system::instance();
2674
        self::validate_context($context);
2675
 
2676
        $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2677
        core_user::require_active_user($user);
2678
 
2679
        if (\core_message\api::can_mark_all_messages_as_read($params['userid'], $params['conversationid'])) {
2680
            \core_message\api::mark_all_messages_as_read($params['userid'], $params['conversationid']);
2681
        } else {
2682
            throw new moodle_exception('accessdenied', 'admin');
2683
        }
2684
    }
2685
 
2686
    /**
2687
     * Mark all conversation messages as read return description.
2688
     *
2689
     * @return external_warnings
2690
     * @since 3.6
2691
     */
2692
    public static function mark_all_conversation_messages_as_read_returns() {
2693
        return null;
2694
    }
2695
 
2696
    /**
2697
     * Returns description of method parameters.
2698
     *
2699
     * @return external_function_parameters
2700
     * @since 3.6
2701
     */
2702
    public static function delete_conversations_by_id_parameters() {
2703
        return new external_function_parameters(
2704
            array(
2705
                'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
2706
                'conversationids' => new external_multiple_structure(
2707
                    new external_value(PARAM_INT, 'The id of the conversation'),
2708
                    'List of conversation IDs'
2709
                ),
2710
            )
2711
        );
2712
    }
2713
 
2714
    /**
2715
     * Deletes a conversation.
2716
     *
2717
     * @param int $userid The user id of who we want to delete the conversation for
2718
     * @param int[] $conversationids The ids of the conversations
2719
     * @return array
2720
     * @throws moodle_exception
2721
     * @since 3.6
2722
     */
2723
    public static function delete_conversations_by_id($userid, array $conversationids) {
2724
        global $CFG;
2725
 
2726
        // Check if private messaging between users is allowed.
2727
        if (empty($CFG->messaging)) {
2728
            throw new moodle_exception('disabled', 'message');
2729
        }
2730
 
2731
        // Validate params.
2732
        $params = [
2733
            'userid' => $userid,
2734
            'conversationids' => $conversationids,
2735
        ];
2736
        $params = self::validate_parameters(self::delete_conversations_by_id_parameters(), $params);
2737
 
2738
        // Validate context.
2739
        $context = context_system::instance();
2740
        self::validate_context($context);
2741
 
2742
        $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2743
        core_user::require_active_user($user);
2744
 
2745
        foreach ($params['conversationids'] as $conversationid) {
2746
            if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
2747
                \core_message\api::delete_conversation_by_id($user->id, $conversationid);
2748
            } else {
2749
                throw new moodle_exception("You do not have permission to delete the conversation '$conversationid'");
2750
            }
2751
        }
2752
 
2753
        return [];
2754
    }
2755
 
2756
    /**
2757
     * Returns description of method result value.
2758
     *
2759
     * @return \core_external\external_description
2760
     * @since 3.6
2761
     */
2762
    public static function delete_conversations_by_id_returns() {
2763
        return new external_warnings();
2764
    }
2765
 
2766
    /**
2767
     * Returns description of method parameters
2768
     *
2769
     * @return external_function_parameters
2770
     * @since 3.1
2771
     */
2772
    public static function delete_message_parameters() {
2773
        return new external_function_parameters(
2774
            array(
2775
                'messageid' => new external_value(PARAM_INT, 'The message id'),
2776
                'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
2777
                'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
2778
            )
2779
        );
2780
    }
2781
 
2782
    /**
2783
     * Deletes a message
2784
     *
2785
     * @param  int $messageid the message id
2786
     * @param  int $userid the user id of who we want to delete the message for
2787
     * @param  bool $read if is a message read (default to true)
2788
     * @return \core_external\external_description
2789
     * @throws moodle_exception
2790
     * @since 3.1
2791
     */
2792
    public static function delete_message($messageid, $userid, $read = true) {
2793
        global $CFG;
2794
 
2795
        // Check if private messaging between users is allowed.
2796
        if (empty($CFG->messaging)) {
2797
            throw new moodle_exception('disabled', 'message');
2798
        }
2799
 
2800
        // Warnings array, it can be empty at the end but is mandatory.
2801
        $warnings = array();
2802
 
2803
        // Validate params.
2804
        $params = array(
2805
            'messageid' => $messageid,
2806
            'userid' => $userid,
2807
            'read' => $read
2808
        );
2809
        $params = self::validate_parameters(self::delete_message_parameters(), $params);
2810
 
2811
        // Validate context.
2812
        $context = context_system::instance();
2813
        self::validate_context($context);
2814
 
2815
        $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2816
        core_user::require_active_user($user);
2817
 
2818
        if (\core_message\api::can_delete_message($user->id, $params['messageid'])) {
2819
            $status = \core_message\api::delete_message($user->id, $params['messageid']);
2820
        } else {
2821
            throw new moodle_exception('You do not have permission to delete this message');
2822
        }
2823
 
2824
        $results = array(
2825
            'status' => $status,
2826
            'warnings' => $warnings
2827
        );
2828
        return $results;
2829
    }
2830
 
2831
    /**
2832
     * Returns description of method result value
2833
     *
2834
     * @return \core_external\external_description
2835
     * @since 3.1
2836
     */
2837
    public static function delete_message_returns() {
2838
        return new external_single_structure(
2839
            array(
2840
                'status' => new external_value(PARAM_BOOL, 'True if the message was deleted, false otherwise'),
2841
                'warnings' => new external_warnings()
2842
            )
2843
        );
2844
    }
2845
 
2846
    /**
2847
     * Returns description of method parameters
2848
     *
2849
     * @return external_function_parameters
2850
     * @since 3.2
2851
     */
2852
    public static function message_processor_config_form_parameters() {
2853
        return new external_function_parameters(
2854
            array(
2855
                'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED),
2856
                'name' => new external_value(PARAM_SAFEDIR, 'The name of the message processor'),
2857
                'formvalues' => new external_multiple_structure(
2858
                    new external_single_structure(
2859
                        array(
2860
                            'name' => new external_value(PARAM_TEXT, 'name of the form element', VALUE_REQUIRED),
2861
                            'value' => new external_value(PARAM_RAW, 'value of the form element', VALUE_REQUIRED),
2862
                        )
2863
                    ),
2864
                    'Config form values',
2865
                    VALUE_REQUIRED
2866
                ),
2867
            )
2868
        );
2869
    }
2870
 
2871
    /**
2872
     * Processes a message processor config form.
2873
     *
2874
     * @param  int $userid the user id
2875
     * @param  string $name the name of the processor
2876
     * @param  array $formvalues the form values
2877
     * @return \core_external\external_description
2878
     * @throws moodle_exception
2879
     * @since 3.2
2880
     */
2881
    public static function message_processor_config_form($userid, $name, $formvalues) {
2882
        global $USER, $CFG;
2883
 
2884
        $params = self::validate_parameters(
2885
            self::message_processor_config_form_parameters(),
2886
            array(
2887
                'userid' => $userid,
2888
                'name' => $name,
2889
                'formvalues' => $formvalues,
2890
            )
2891
        );
2892
 
2893
        $user = self::validate_preferences_permissions($params['userid']);
2894
 
2895
        $processor = get_message_processor($params['name']);
2896
        $preferences = [];
2897
        $form = new stdClass();
2898
 
2899
        foreach ($params['formvalues'] as $formvalue) {
2900
            // Curly braces to ensure interpretation is consistent between
2901
            // php 5 and php 7.
2902
            $form->{$formvalue['name']} = $formvalue['value'];
2903
        }
2904
 
2905
        $processor->process_form($form, $preferences);
2906
 
2907
        if (!empty($preferences)) {
2908
            set_user_preferences($preferences, $params['userid']);
2909
        }
2910
    }
2911
 
2912
    /**
2913
     * Returns description of method result value
2914
     *
2915
     * @return \core_external\external_description
2916
     * @since 3.2
2917
     */
2918
    public static function message_processor_config_form_returns() {
2919
        return null;
2920
    }
2921
 
2922
    /**
2923
     * Returns description of method parameters
2924
     *
2925
     * @return external_function_parameters
2926
     * @since 3.2
2927
     */
2928
    public static function get_message_processor_parameters() {
2929
        return new external_function_parameters(
2930
            array(
2931
                'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user'),
2932
                'name' => new external_value(PARAM_SAFEDIR, 'The name of the message processor', VALUE_REQUIRED),
2933
            )
2934
        );
2935
    }
2936
 
2937
    /**
2938
     * Get a message processor.
2939
     *
2940
     * @param int $userid
2941
     * @param string $name the name of the processor
2942
     * @return \core_external\external_description
2943
     * @throws moodle_exception
2944
     * @since 3.2
2945
     */
2946
    public static function get_message_processor($userid, $name) {
2947
        global $USER, $PAGE, $CFG;
2948
 
2949
        // Check if messaging is enabled.
2950
        if (empty($CFG->messaging)) {
2951
            throw new moodle_exception('disabled', 'message');
2952
        }
2953
 
2954
        $params = self::validate_parameters(
2955
            self::get_message_processor_parameters(),
2956
            array(
2957
                'userid' => $userid,
2958
                'name' => $name,
2959
            )
2960
        );
2961
 
2962
        if (empty($params['userid'])) {
2963
            $params['userid'] = $USER->id;
2964
        }
2965
 
2966
        $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2967
        core_user::require_active_user($user);
2968
        self::validate_context(context_user::instance($params['userid']));
2969
 
2970
        $processor = get_message_processor($params['name']);
2971
 
2972
        $processoroutput = new \core_message\output\processor($processor, $user);
2973
        $renderer = $PAGE->get_renderer('core_message');
2974
 
2975
        return $processoroutput->export_for_template($renderer);
2976
    }
2977
 
2978
    /**
2979
     * Returns description of method result value
2980
     *
2981
     * @return \core_external\external_description
2982
     * @since 3.2
2983
     */
2984
    public static function get_message_processor_returns() {
2985
        return new external_function_parameters(
2986
            array(
2987
                'systemconfigured' => new external_value(PARAM_BOOL, 'Site configuration status'),
2988
                'userconfigured' => new external_value(PARAM_BOOL, 'The user configuration status'),
2989
            )
2990
        );
2991
    }
2992
 
2993
    /**
2994
     * Check that the user has enough permission to retrieve message or notifications preferences.
2995
     *
2996
     * @param  int $userid the user id requesting the preferences
2997
     * @return stdClass full user object
2998
     * @throws moodle_exception
2999
     * @since  Moodle 3.2
3000
     */
3001
    protected static function validate_preferences_permissions($userid) {
3002
        global $USER;
3003
 
3004
        if (empty($userid)) {
3005
            $user = $USER;
3006
        } else {
3007
            $user = core_user::get_user($userid, '*', MUST_EXIST);
3008
            core_user::require_active_user($user);
3009
        }
3010
 
3011
        $systemcontext = context_system::instance();
3012
        self::validate_context($systemcontext);
3013
 
3014
        // Check access control.
3015
        if ($user->id == $USER->id) {
3016
            // Editing own message profile.
3017
            require_capability('moodle/user:editownmessageprofile', $systemcontext);
3018
        } else {
3019
            // Teachers, parents, etc.
3020
            $personalcontext = context_user::instance($user->id);
3021
            require_capability('moodle/user:editmessageprofile', $personalcontext);
3022
        }
3023
        return $user;
3024
    }
3025
 
3026
    /**
3027
     * Returns a notification or message preference structure.
3028
     *
3029
     * @return external_single_structure the structure
3030
     * @since  Moodle 3.2
3031
     * @todo Remove loggedin and loggedoff from processors structure on MDL-73284.
3032
     */
3033
    protected static function get_preferences_structure() {
3034
        return new external_single_structure(
3035
            array(
3036
                'userid' => new external_value(PARAM_INT, 'User id'),
3037
                'disableall' => new external_value(PARAM_INT, 'Whether all the preferences are disabled'),
3038
                'processors' => new external_multiple_structure(
3039
                    new external_single_structure(
3040
                        array(
3041
                            'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3042
                            'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3043
                            'hassettings' => new external_value(PARAM_BOOL, 'Whether has settings'),
3044
                            'contextid' => new external_value(PARAM_INT, 'Context id'),
3045
                            'userconfigured' => new external_value(PARAM_INT, 'Whether is configured by the user'),
3046
                        )
3047
                    ),
3048
                    'Config form values'
3049
                ),
3050
                'components' => new external_multiple_structure(
3051
                    new external_single_structure(
3052
                        array(
3053
                            'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3054
                            'notifications' => new external_multiple_structure(
3055
                                new external_single_structure(
3056
                                    array(
3057
                                        'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3058
                                        'preferencekey' => new external_value(PARAM_ALPHANUMEXT, 'Preference key'),
3059
                                        'processors' => new external_multiple_structure(
3060
                                            new external_single_structure(
3061
                                                array(
3062
                                                    'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3063
                                                    'name' => new external_value(PARAM_PLUGIN, 'Processor name'),
3064
                                                    'locked' => new external_value(PARAM_BOOL, 'Is locked by admin?'),
3065
                                                    'lockedmessage' => new external_value(PARAM_TEXT,
3066
                                                        'Text to display if locked', VALUE_OPTIONAL),
3067
                                                    'userconfigured' => new external_value(PARAM_INT, 'Is configured?'),
3068
                                                    'loggedin' => new external_single_structure(
3069
                                                        array(
3070
                                                            'name' => new external_value(PARAM_NOTAGS, 'Name'),
3071
                                                            'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3072
                                                            'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3073
                                                        ),
3074
                                                        'DEPRECATED ATTRIBUTE -
3075
                                                        Kept for backward compatibility, use enabled instead.',
3076
                                                    ),
3077
                                                    'loggedoff' => new external_single_structure(
3078
                                                        array(
3079
                                                            'name' => new external_value(PARAM_NOTAGS, 'Name'),
3080
                                                            'displayname' => new external_value(PARAM_TEXT, 'Display name'),
3081
                                                            'checked' => new external_value(PARAM_BOOL, 'Is checked?'),
3082
                                                        ),
3083
                                                        'DEPRECATED ATTRIBUTE -
3084
                                                        Kept for backward compatibility, use enabled instead.',
3085
                                                    ),
3086
                                                    'enabled' => new external_value(PARAM_BOOL, 'Is enabled?'),
3087
                                                )
3088
                                            ),
3089
                                            'Processors values for this notification'
3090
                                        ),
3091
                                    )
3092
                                ),
3093
                                'List of notificaitons for the component'
3094
                            ),
3095
                        )
3096
                    ),
3097
                    'Available components'
3098
                ),
3099
            )
3100
        );
3101
    }
3102
 
3103
    /**
3104
     * Returns description of method parameters
3105
     *
3106
     * @return external_function_parameters
3107
     * @since 3.2
3108
     */
3109
    public static function get_user_notification_preferences_parameters() {
3110
        return new external_function_parameters(
3111
            array(
3112
                'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3113
            )
3114
        );
3115
    }
3116
 
3117
    /**
3118
     * Get the notification preferences for a given user.
3119
     *
3120
     * @param int $userid id of the user, 0 for current user
3121
     * @return \core_external\external_description
3122
     * @throws moodle_exception
3123
     * @since 3.2
3124
     */
3125
    public static function get_user_notification_preferences($userid = 0) {
3126
        global $PAGE;
3127
 
3128
        $params = self::validate_parameters(
3129
            self::get_user_notification_preferences_parameters(),
3130
            array(
3131
                'userid' => $userid,
3132
            )
3133
        );
3134
        $user = self::validate_preferences_permissions($params['userid']);
3135
 
3136
        $processors = get_message_processors();
3137
        $providers = message_get_providers_for_user($user->id);
3138
        $preferences = \core_message\api::get_all_message_preferences($processors, $providers, $user);
3139
        $notificationlist = new \core_message\output\preferences\notification_list($processors, $providers, $preferences, $user);
3140
 
3141
        $renderer = $PAGE->get_renderer('core_message');
3142
 
3143
        $result = array(
3144
            'warnings' => array(),
3145
            'preferences' => $notificationlist->export_for_template($renderer)
3146
        );
3147
        return $result;
3148
    }
3149
 
3150
    /**
3151
     * Returns description of method result value
3152
     *
3153
     * @return \core_external\external_description
3154
     * @since 3.2
3155
     */
3156
    public static function get_user_notification_preferences_returns() {
3157
        return new external_function_parameters(
3158
            array(
3159
                'preferences' => self::get_preferences_structure(),
3160
                'warnings' => new external_warnings(),
3161
            )
3162
        );
3163
    }
3164
 
3165
    /**
3166
     * Returns description of method parameters
3167
     *
3168
     * @return external_function_parameters
3169
     * @since 3.2
3170
     */
3171
    public static function get_user_message_preferences_parameters() {
3172
        return new external_function_parameters(
3173
            array(
3174
                'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3175
            )
3176
        );
3177
    }
3178
 
3179
    /**
3180
     * Get the notification preferences for a given user.
3181
     *
3182
     * @param int $userid id of the user, 0 for current user
3183
     * @return \core_external\external_description
3184
     * @throws moodle_exception
3185
     * @since 3.2
3186
     */
3187
    public static function get_user_message_preferences($userid = 0) {
3188
        global $CFG, $PAGE;
3189
 
3190
        $params = self::validate_parameters(
3191
            self::get_user_message_preferences_parameters(),
3192
            array(
3193
                'userid' => $userid,
3194
            )
3195
        );
3196
 
3197
        $user = self::validate_preferences_permissions($params['userid']);
3198
 
3199
        // Filter out enabled, available system_configured and user_configured processors only.
3200
        $readyprocessors = array_filter(get_message_processors(), function($processor) {
3201
            return $processor->enabled &&
3202
                $processor->configured &&
3203
                $processor->object->is_user_configured() &&
3204
                // Filter out processors that don't have and message preferences to configure.
3205
                $processor->object->has_message_preferences();
3206
        });
3207
 
3208
        $providers = array_filter(message_get_providers_for_user($user->id), function($provider) {
3209
            return $provider->component === 'moodle';
3210
        });
3211
        $preferences = \core_message\api::get_all_message_preferences($readyprocessors, $providers, $user);
3212
        $notificationlistoutput = new \core_message\output\preferences\message_notification_list($readyprocessors,
3213
            $providers, $preferences, $user);
3214
 
3215
        $renderer = $PAGE->get_renderer('core_message');
3216
 
3217
        $entertosend = get_user_preferences('message_entertosend', $CFG->messagingdefaultpressenter, $user);
3218
 
3219
        $result = array(
3220
            'warnings' => array(),
3221
            'preferences' => $notificationlistoutput->export_for_template($renderer),
3222
            'blocknoncontacts' => \core_message\api::get_user_privacy_messaging_preference($user->id),
3223
            'entertosend' => $entertosend
3224
        );
3225
        return $result;
3226
    }
3227
 
3228
    /**
3229
     * Returns description of method result value
3230
     *
3231
     * @return \core_external\external_description
3232
     * @since 3.2
3233
     */
3234
    public static function get_user_message_preferences_returns() {
3235
        return new external_function_parameters(
3236
            array(
3237
                'preferences' => self::get_preferences_structure(),
3238
                'blocknoncontacts' => new external_value(PARAM_INT, 'Privacy messaging setting to define who can message you'),
3239
                'entertosend' => new external_value(PARAM_BOOL, 'User preference for using enter to send messages'),
3240
                'warnings' => new external_warnings(),
3241
            )
3242
        );
3243
    }
3244
 
3245
    /**
3246
     * Returns description of method parameters for the favourite_conversations() method.
3247
     *
3248
     * @return external_function_parameters
3249
     */
3250
    public static function set_favourite_conversations_parameters() {
3251
        return new external_function_parameters(
3252
            array(
3253
                'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0),
3254
                'conversations' => new external_multiple_structure(
3255
                    new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0)
3256
                )
3257
            )
3258
        );
3259
    }
3260
 
3261
    /**
3262
     * Favourite a conversation, or list of conversations for a user.
3263
     *
3264
     * @param int $userid the id of the user, or 0 for the current user.
3265
     * @param array $conversationids the list of conversations ids to favourite.
3266
     * @return array
3267
     * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3268
     */
3269
    public static function set_favourite_conversations(int $userid, array $conversationids) {
3270
        global $CFG, $USER;
3271
 
3272
        // All the business logic checks that really shouldn't be in here.
3273
        if (empty($CFG->messaging)) {
3274
            throw new moodle_exception('disabled', 'message');
3275
        }
3276
        $params = [
3277
            'userid' => $userid,
3278
            'conversations' => $conversationids
3279
        ];
3280
        $params = self::validate_parameters(self::set_favourite_conversations_parameters(), $params);
3281
        $systemcontext = context_system::instance();
3282
        self::validate_context($systemcontext);
3283
 
3284
        if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3285
            throw new moodle_exception('You do not have permission to perform this action.');
3286
        }
3287
 
3288
        foreach ($params['conversations'] as $conversationid) {
3289
            \core_message\api::set_favourite_conversation($conversationid, $params['userid']);
3290
        }
3291
 
3292
        return [];
3293
    }
3294
 
3295
    /**
3296
     * Return a description of the returns for the create_user_favourite_conversations() method.
3297
     *
3298
     * @return \core_external\external_description
3299
     */
3300
    public static function set_favourite_conversations_returns() {
3301
        return new external_warnings();
3302
    }
3303
 
3304
    /**
3305
     * Returns description of method parameters for unfavourite_conversations() method.
3306
     *
3307
     * @return external_function_parameters
3308
     */
3309
    public static function unset_favourite_conversations_parameters() {
3310
        return new external_function_parameters(
3311
            array(
3312
                'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0),
3313
                'conversations' => new external_multiple_structure(
3314
                    new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0)
3315
                )
3316
            )
3317
        );
3318
    }
3319
 
3320
    /**
3321
     * Unfavourite a conversation, or list of conversations for a user.
3322
     *
3323
     * @param int $userid the id of the user, or 0 for the current user.
3324
     * @param array $conversationids the list of conversations ids unset as favourites.
3325
     * @return array
3326
     * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3327
     */
3328
    public static function unset_favourite_conversations(int $userid, array $conversationids) {
3329
        global $CFG, $USER;
3330
 
3331
        // All the business logic checks that really shouldn't be in here.
3332
        if (empty($CFG->messaging)) {
3333
            throw new moodle_exception('disabled', 'message');
3334
        }
3335
        $params = [
3336
            'userid' => $userid,
3337
            'conversations' => $conversationids
3338
        ];
3339
        $params = self::validate_parameters(self::unset_favourite_conversations_parameters(), $params);
3340
        $systemcontext = context_system::instance();
3341
        self::validate_context($systemcontext);
3342
 
3343
        if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3344
            throw new moodle_exception('You do not have permission to perform this action.');
3345
        }
3346
 
3347
        foreach ($params['conversations'] as $conversationid) {
3348
            \core_message\api::unset_favourite_conversation($conversationid, $params['userid']);
3349
        }
3350
 
3351
        return [];
3352
    }
3353
 
3354
    /**
3355
     * Unset favourite conversations return description.
3356
     *
3357
     * @return \core_external\external_description
3358
     */
3359
    public static function unset_favourite_conversations_returns() {
3360
        return new external_warnings();
3361
    }
3362
 
3363
    /**
3364
     * Returns description of method parameters for get_member_info() method.
3365
     *
3366
     * @return external_function_parameters
3367
     */
3368
    public static function get_member_info_parameters() {
3369
        return new external_function_parameters(
3370
            array(
3371
                'referenceuserid' => new external_value(PARAM_INT, 'id of the user'),
3372
                'userids' => new external_multiple_structure(
3373
                    new external_value(PARAM_INT, 'id of members to get')
3374
                ),
3375
                'includecontactrequests' => new external_value(PARAM_BOOL, 'include contact requests in response', VALUE_DEFAULT, false),
3376
                'includeprivacyinfo' => new external_value(PARAM_BOOL, 'include privacy info in response', VALUE_DEFAULT, false)
3377
            )
3378
        );
3379
    }
3380
 
3381
    /**
3382
     * Returns conversation member info for the supplied users, relative to the supplied referenceuserid.
3383
     *
3384
     * This is the basic structure used when returning members, and includes information about the relationship between each member
3385
     * and the referenceuser, such as a whether the referenceuser has marked the member as a contact, or has blocked them.
3386
     *
3387
     * @param int $referenceuserid the id of the user which check contact and blocked status.
3388
     * @param array $userids
3389
     * @return array the array of objects containing member info.
3390
     * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3391
     */
3392
    public static function get_member_info(
3393
        int $referenceuserid,
3394
        array $userids,
3395
        bool $includecontactrequests = false,
3396
        bool $includeprivacyinfo = false
3397
    ) {
3398
        global $CFG, $USER;
3399
 
3400
        // All the business logic checks that really shouldn't be in here.
3401
        if (empty($CFG->messaging)) {
3402
            throw new moodle_exception('disabled', 'message');
3403
        }
3404
        $params = [
3405
            'referenceuserid' => $referenceuserid,
3406
            'userids' => $userids,
3407
            'includecontactrequests' => $includecontactrequests,
3408
            'includeprivacyinfo' => $includeprivacyinfo
3409
        ];
3410
        $params = self::validate_parameters(self::get_member_info_parameters(), $params);
3411
        $systemcontext = context_system::instance();
3412
        self::validate_context($systemcontext);
3413
 
3414
        if (($USER->id != $referenceuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3415
            throw new moodle_exception('You do not have permission to perform this action.');
3416
        }
3417
 
3418
        return \core_message\helper::get_member_info(
3419
            $params['referenceuserid'],
3420
            $params['userids'],
3421
            $params['includecontactrequests'],
3422
            $params['includeprivacyinfo']
3423
        );
3424
    }
3425
 
3426
    /**
3427
     * Get member info return description.
3428
     *
3429
     * @return \core_external\external_description
3430
     */
3431
    public static function get_member_info_returns() {
3432
        return new external_multiple_structure(
3433
            self::get_conversation_member_structure()
3434
        );
3435
    }
3436
 
3437
    /**
3438
     * Returns description of method parameters for get_conversation_counts() method.
3439
     *
3440
     * @return external_function_parameters
3441
     */
3442
    public static function get_conversation_counts_parameters() {
3443
        return new external_function_parameters(
3444
            [
3445
                'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3446
            ]
3447
        );
3448
    }
3449
 
3450
    /**
3451
     * Returns an array of conversation counts for the various types of conversations, including favourites.
3452
     *
3453
     * Return format:
3454
     * [
3455
     *     'favourites' => 0,
3456
     *     'types' => [
3457
     *          \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
3458
     *          \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => 0
3459
     *      ]
3460
     * ]
3461
     *
3462
     * @param int $userid the id of the user whose counts we are fetching.
3463
     * @return array the array of conversation counts, indexed by type.
3464
     * @throws moodle_exception if the current user cannot perform this action.
3465
     */
3466
    public static function get_conversation_counts(int $userid) {
3467
        global $CFG, $USER;
3468
 
3469
        // All the business logic checks that really shouldn't be in here.
3470
        if (empty($CFG->messaging)) {
3471
            throw new moodle_exception('disabled', 'message');
3472
        }
3473
 
3474
        if (empty($userid)) {
3475
            $userid = $USER->id;
3476
        }
3477
 
3478
        $params = ['userid' => $userid];
3479
        $params = self::validate_parameters(self::get_conversation_counts_parameters(), $params);
3480
 
3481
        $systemcontext = context_system::instance();
3482
        self::validate_context($systemcontext);
3483
 
3484
        if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3485
            throw new moodle_exception('You do not have permission to perform this action.');
3486
        }
3487
 
3488
        return \core_message\api::get_conversation_counts($params['userid']);
3489
    }
3490
 
3491
    /**
3492
     * Get conversation counts return description.
3493
     *
3494
     * @return \core_external\external_description
3495
     */
3496
    public static function get_conversation_counts_returns() {
3497
        return new external_single_structure(
3498
            [
3499
                'favourites' => new external_value(PARAM_INT, 'Total number of favourite conversations'),
3500
                'types' => new external_single_structure(
3501
                    [
3502
                        \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => new external_value(PARAM_INT,
3503
                            'Total number of individual conversations'),
3504
                        \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => new external_value(PARAM_INT,
3505
                            'Total number of group conversations'),
3506
                        \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF => new external_value(PARAM_INT,
3507
                            'Total number of self conversations'),
3508
                    ]
3509
                ),
3510
            ]
3511
        );
3512
    }
3513
 
3514
    /**
3515
     * Returns description of method parameters for get_unread_conversation_counts() method.
3516
     *
3517
     * @return external_function_parameters
3518
     */
3519
    public static function get_unread_conversation_counts_parameters() {
3520
        return new external_function_parameters(
3521
            [
3522
                'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3523
            ]
3524
        );
3525
    }
3526
 
3527
    /**
3528
     * Returns an array of unread conversation counts for the various types of conversations, including favourites.
3529
     *
3530
     * Return format:
3531
     * [
3532
     *     'favourites' => 0,
3533
     *     'types' => [
3534
     *          \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
3535
     *          \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => 0
3536
     *      ]
3537
     * ]
3538
     *
3539
     * @param int $userid the id of the user whose counts we are fetching.
3540
     * @return array the array of unread conversation counts, indexed by type.
3541
     * @throws moodle_exception if the current user cannot perform this action.
3542
     */
3543
    public static function get_unread_conversation_counts(int $userid) {
3544
        global $CFG, $USER;
3545
 
3546
        // All the business logic checks that really shouldn't be in here.
3547
        if (empty($CFG->messaging)) {
3548
            throw new moodle_exception('disabled', 'message');
3549
        }
3550
 
3551
        if (empty($userid)) {
3552
            $userid = $USER->id;
3553
        }
3554
 
3555
        $params = ['userid' => $userid];
3556
        $params = self::validate_parameters(self::get_unread_conversation_counts_parameters(), $params);
3557
 
3558
        $systemcontext = context_system::instance();
3559
        self::validate_context($systemcontext);
3560
 
3561
        if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3562
            throw new moodle_exception('You do not have permission to perform this action.');
3563
        }
3564
 
3565
        return \core_message\api::get_unread_conversation_counts($params['userid']);
3566
    }
3567
 
3568
    /**
3569
     * Get unread conversation counts return description.
3570
     *
3571
     * @return \core_external\external_description
3572
     */
3573
    public static function get_unread_conversation_counts_returns() {
3574
        return new external_single_structure(
3575
            [
3576
                'favourites' => new external_value(PARAM_INT, 'Total number of unread favourite conversations'),
3577
                'types' => new external_single_structure(
3578
                    [
3579
                        \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => new external_value(PARAM_INT,
3580
                            'Total number of unread individual conversations'),
3581
                        \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => new external_value(PARAM_INT,
3582
                            'Total number of unread group conversations'),
3583
                        \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF => new external_value(PARAM_INT,
3584
                            'Total number of unread self conversations'),
3585
                    ]
3586
                ),
3587
            ]
3588
        );
3589
    }
3590
 
3591
    /**
3592
     * Returns description of method parameters
3593
     *
3594
     * @return external_function_parameters
3595
     * @since 3.7
3596
     */
3597
    public static function delete_message_for_all_users_parameters() {
3598
        return new external_function_parameters(
3599
            array(
3600
                'messageid' => new external_value(PARAM_INT, 'The message id'),
3601
                'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for all users')
3602
            )
3603
        );
3604
    }
3605
    /**
3606
     * Deletes a message for all users
3607
     *
3608
     * @param  int $messageid the message id
3609
     * @param  int $userid the user id of who we want to delete the message for all users, is no longer used.
3610
     * @return \core_external\external_description
3611
     * @throws moodle_exception
3612
     * @since 3.7
3613
     */
3614
    public static function delete_message_for_all_users(int $messageid, int $userid) {
3615
        global $CFG, $USER;
3616
 
3617
        // Check if private messaging between users is allowed.
3618
        if (empty($CFG->messaging)) {
3619
            throw new moodle_exception('disabled', 'message');
3620
        }
3621
 
3622
        // Validate params.
3623
        $params = array(
3624
            'messageid' => $messageid,
3625
            'userid' => $userid
3626
        );
3627
        $params = self::validate_parameters(self::delete_message_for_all_users_parameters(), $params);
3628
 
3629
        // Validate context.
3630
        $context = context_system::instance();
3631
        self::validate_context($context);
3632
 
3633
        core_user::require_active_user($USER);
3634
 
3635
        // Checks if a user can delete a message for all users.
3636
        if (core_message\api::can_delete_message_for_all_users($USER->id, $params['messageid'])) {
3637
            \core_message\api::delete_message_for_all_users($params['messageid']);
3638
        } else {
3639
            throw new moodle_exception('You do not have permission to delete this message for everyone.');
3640
        }
3641
 
3642
        return [];
3643
    }
3644
    /**
3645
     * Returns description of method result value
3646
     *
3647
     * @return \core_external\external_description
3648
     * @since 3.7
3649
     */
3650
    public static function delete_message_for_all_users_returns() {
3651
        return new external_warnings();
3652
    }
3653
}