Proyectos de Subversion Moodle

Rev

Rev 1 | | Comparar con el anterior | 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;
1441 ariadna 215
                $errormessage = get_string('usercantbemessaged', 'message');
1 efrain 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'),
1441 ariadna 1072
            'cancreatecontact' => new external_value(PARAM_BOOL, 'Is the user permitted to add a contact'),
1 efrain 1073
        ];
1074
 
1075
        $result['contactrequests'] = new external_multiple_structure(
1076
            new external_single_structure(
1077
                [
1078
                    'id' => new external_value(PARAM_INT, 'The id of the contact request'),
1079
                    'userid' => new external_value(PARAM_INT, 'The id of the user who created the contact request'),
1080
                    'requesteduserid' => new external_value(PARAM_INT, 'The id of the user confirming the request'),
1081
                    'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the contact request'),
1082
                ]
1083
            ), 'The contact requests', VALUE_OPTIONAL
1084
        );
1085
 
1086
        $result['conversations'] = new external_multiple_structure(new external_single_structure(
1087
            array(
1088
                'id' => new external_value(PARAM_INT, 'Conversations id'),
1089
                'type' => new external_value(PARAM_INT, 'Conversation type: private or public'),
1090
                'name' => new external_value(PARAM_RAW, 'Multilang compatible conversation name'. VALUE_OPTIONAL),
1091
                'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the conversation'),
1092
            ), 'information about conversation', VALUE_OPTIONAL),
1093
            'Conversations between users', VALUE_OPTIONAL
1094
        );
1095
 
1096
        return new external_single_structure(
1097
            $result
1098
        );
1099
    }
1100
 
1101
    /**
1102
     * Return the structure of a message area message.
1103
     *
1104
     * @return external_single_structure
1105
     * @since Moodle 3.6
1106
     */
1107
    private static function get_conversation_message_structure() {
1108
        return new external_single_structure(
1109
            array(
1110
                'id' => new external_value(PARAM_INT, 'The id of the message'),
1111
                'useridfrom' => new external_value(PARAM_INT, 'The id of the user who sent the message'),
1112
                'text' => new external_value(PARAM_RAW, 'The text of the message'),
1113
                'timecreated' => new external_value(PARAM_INT, 'The timecreated timestamp for the message'),
1114
            )
1115
        );
1116
    }
1117
 
1118
    /**
1119
     * Get messagearea message search users parameters.
1120
     *
1121
     * @return external_function_parameters
1122
     * @since 3.6
1123
     */
1124
    public static function message_search_users_parameters() {
1125
        return new external_function_parameters(
1126
            array(
1127
                'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1128
                'search' => new external_value(PARAM_RAW, 'The string being searched'),
1129
                'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1130
                'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1131
            )
1132
        );
1133
    }
1134
 
1135
    /**
1136
     * Get search users results.
1137
     *
1138
     * @param int $userid The id of the user who is performing the search
1139
     * @param string $search The string being searched
1140
     * @param int $limitfrom
1141
     * @param int $limitnum
1142
     * @return array
1143
     * @throws moodle_exception
1144
     * @since 3.6
1145
     */
1146
    public static function message_search_users($userid, $search, $limitfrom = 0, $limitnum = 0) {
1147
        global $USER;
1148
 
1149
        $systemcontext = context_system::instance();
1150
 
1151
        $params = array(
1152
            'userid' => $userid,
1153
            'search' => $search,
1154
            'limitfrom' => $limitfrom,
1155
            'limitnum' => $limitnum
1156
        );
1157
        $params = self::validate_parameters(self::message_search_users_parameters(), $params);
1158
        self::validate_context($systemcontext);
1159
 
1160
        if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1161
            throw new moodle_exception('You do not have permission to perform this action.');
1162
        }
1163
 
1164
        list($contacts, $noncontacts) = \core_message\api::message_search_users(
1165
            $params['userid'],
1166
            $params['search'],
1167
            $params['limitfrom'],
1168
            $params['limitnum']);
1169
 
1170
        return array('contacts' => $contacts, 'noncontacts' => $noncontacts);
1171
    }
1172
 
1173
    /**
1174
     * Get messagearea message search users returns.
1175
     *
1176
     * @return external_single_structure
1177
     * @since 3.2
1178
     */
1179
    public static function message_search_users_returns() {
1180
        return new external_single_structure(
1181
            array(
1182
                'contacts' => new external_multiple_structure(
1183
                    self::get_conversation_member_structure()
1184
                ),
1185
                'noncontacts' => new external_multiple_structure(
1186
                    self::get_conversation_member_structure()
1187
                )
1188
            )
1189
        );
1190
    }
1191
 
1192
    /**
1193
     * Get messagearea search messages parameters.
1194
     *
1195
     * @return external_function_parameters
1196
     * @since 3.2
1197
     */
1198
    public static function data_for_messagearea_search_messages_parameters() {
1199
        return new external_function_parameters(
1200
            array(
1201
                'userid' => new external_value(PARAM_INT, 'The id of the user who is performing the search'),
1202
                'search' => new external_value(PARAM_RAW, 'The string being searched'),
1203
                'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1204
                'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1205
            )
1206
        );
1207
    }
1208
 
1209
    /**
1210
     * Get messagearea search messages results.
1211
     *
1212
     * @param int $userid The id of the user who is performing the search
1213
     * @param string $search The string being searched
1214
     * @param int $limitfrom
1215
     * @param int $limitnum
1216
     * @return stdClass
1217
     * @throws moodle_exception
1218
     * @since 3.2
1219
     */
1220
    public static function data_for_messagearea_search_messages($userid, $search, $limitfrom = 0, $limitnum = 0) {
1221
        global $CFG, $USER;
1222
 
1223
        // Check if messaging is enabled.
1224
        if (empty($CFG->messaging)) {
1225
            throw new moodle_exception('disabled', 'message');
1226
        }
1227
 
1228
        $systemcontext = context_system::instance();
1229
 
1230
        $params = array(
1231
            'userid' => $userid,
1232
            'search' => $search,
1233
            'limitfrom' => $limitfrom,
1234
            'limitnum' => $limitnum
1235
 
1236
        );
1237
        $params = self::validate_parameters(self::data_for_messagearea_search_messages_parameters(), $params);
1238
        self::validate_context($systemcontext);
1239
 
1240
        if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1241
            throw new moodle_exception('You do not have permission to perform this action.');
1242
        }
1243
 
1244
        $messages = \core_message\api::search_messages(
1245
            $params['userid'],
1246
            $params['search'],
1247
            $params['limitfrom'],
1248
            $params['limitnum']
1249
        );
1250
 
1251
        $data = new \stdClass();
1252
        $data->contacts = [];
1253
        foreach ($messages as $message) {
1254
            $contact = new \stdClass();
1255
            $contact->userid = $message->userid;
1256
            $contact->fullname = $message->fullname;
1257
            $contact->profileimageurl = $message->profileimageurl;
1258
            $contact->profileimageurlsmall = $message->profileimageurlsmall;
1259
            $contact->messageid = $message->messageid;
1260
            $contact->ismessaging = $message->ismessaging;
1261
            $contact->sentfromcurrentuser = false;
1262
            if ($message->lastmessage) {
1263
                if ($message->userid !== $message->useridfrom) {
1264
                    $contact->sentfromcurrentuser = true;
1265
                }
1266
                $contact->lastmessage = shorten_text($message->lastmessage, 60);
1267
            } else {
1268
                $contact->lastmessage = null;
1269
            }
1270
            $contact->lastmessagedate = $message->lastmessagedate;
1271
            $contact->showonlinestatus = is_null($message->isonline) ? false : true;
1272
            $contact->isonline = $message->isonline;
1273
            $contact->isblocked = $message->isblocked;
1274
            $contact->isread = $message->isread;
1275
            $contact->unreadcount = $message->unreadcount;
1276
            $contact->conversationid = $message->conversationid;
1277
 
1278
            $data->contacts[] = $contact;
1279
        }
1280
 
1281
        return $data;
1282
    }
1283
 
1284
    /**
1285
     * Get messagearea search messages returns.
1286
     *
1287
     * @return external_single_structure
1288
     * @since 3.2
1289
     */
1290
    public static function data_for_messagearea_search_messages_returns() {
1291
        return new external_single_structure(
1292
            array(
1293
                'contacts' => new external_multiple_structure(
1294
                    self::get_messagearea_contact_structure()
1295
                )
1296
            )
1297
        );
1298
    }
1299
 
1300
    /**
1301
     * Get conversations parameters.
1302
     *
1303
     * @return external_function_parameters
1304
     * @since 3.6
1305
     */
1306
    public static function get_conversations_parameters() {
1307
        return new external_function_parameters(
1308
            array(
1309
                'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1310
                'limitfrom' => new external_value(PARAM_INT, 'The offset to start at', VALUE_DEFAULT, 0),
1311
                'limitnum' => new external_value(PARAM_INT, 'Limit number of conversations to this', VALUE_DEFAULT, 0),
1312
                'type' => new external_value(PARAM_INT, 'Filter by type', VALUE_DEFAULT, null),
1313
                'favourites' => new external_value(PARAM_BOOL, 'Whether to restrict the results to contain NO favourite
1314
                conversations (false), ONLY favourite conversation (true), or ignore any restriction altogether (null)',
1315
                    VALUE_DEFAULT, null),
1316
                'mergeself' => new external_value(PARAM_BOOL, 'Whether to include self-conversations (true) or ONLY private
1317
                    conversations (false) when private conversations are requested.',
1318
                    VALUE_DEFAULT, false),
1319
            )
1320
        );
1321
    }
1322
 
1323
    /**
1324
     * Get the list of conversations for the user.
1325
     *
1326
     * @param int $userid The id of the user who is performing the search
1327
     * @param int $limitfrom
1328
     * @param int $limitnum
1329
     * @param int|null $type
1330
     * @param bool|null $favourites
1331
     * @param bool $mergeself whether to include self-conversations (true) or ONLY private conversations (false)
1332
     *             when private conversations are requested.
1333
     * @return stdClass
1334
     * @throws \moodle_exception if the messaging feature is disabled on the site.
1335
     * @since 3.2
1336
     */
1441 ariadna 1337
    public static function get_conversations($userid, $limitfrom = 0, $limitnum = 0, ?int $type = null, ?bool $favourites = null,
1 efrain 1338
            bool $mergeself = false) {
1339
        global $CFG, $USER;
1340
 
1341
        // All the standard BL checks.
1342
        if (empty($CFG->messaging)) {
1343
            throw new moodle_exception('disabled', 'message');
1344
        }
1345
 
1346
        $params = array(
1347
            'userid' => $userid,
1348
            'limitfrom' => $limitfrom,
1349
            'limitnum' => $limitnum,
1350
            'type' => $type,
1351
            'favourites' => $favourites,
1352
            'mergeself' => $mergeself
1353
        );
1354
        $params = self::validate_parameters(self::get_conversations_parameters(), $params);
1355
 
1356
        $systemcontext = context_system::instance();
1357
        self::validate_context($systemcontext);
1358
 
1359
        if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1360
            throw new moodle_exception('You do not have permission to perform this action.');
1361
        }
1362
 
1363
        $conversations = \core_message\api::get_conversations(
1364
            $params['userid'],
1365
            $params['limitfrom'],
1366
            $params['limitnum'],
1367
            $params['type'],
1368
            $params['favourites'],
1369
            $params['mergeself']
1370
        );
1371
 
1372
        return (object) ['conversations' => $conversations];
1373
    }
1374
 
1375
    /**
1376
     * Get conversations returns.
1377
     *
1378
     * @return external_single_structure
1379
     * @since 3.6
1380
     */
1381
    public static function get_conversations_returns() {
1382
        return new external_single_structure(
1383
            [
1384
                'conversations' => new external_multiple_structure(
1385
                    self::get_conversation_structure(true)
1386
                )
1387
            ]
1388
        );
1389
    }
1390
 
1391
    /**
1392
     * Get conversation parameters.
1393
     *
1394
     * @return external_function_parameters
1395
     */
1396
    public static function get_conversation_parameters() {
1397
        return new external_function_parameters(
1398
            array(
1399
                'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1400
                'conversationid' => new external_value(PARAM_INT, 'The id of the conversation to fetch'),
1401
                'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1402
                'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1403
                'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1404
                'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1405
                'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1406
                'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1407
                'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1408
            )
1409
        );
1410
    }
1411
 
1412
    /**
1413
     * Get a single conversation.
1414
     *
1415
     * @param int $userid The user id to get the conversation for
1416
     * @param int $conversationid The id of the conversation to fetch
1417
     * @param bool $includecontactrequests Should contact requests be included between members
1418
     * @param bool $includeprivacyinfo Should privacy info be included between members
1419
     * @param int $memberlimit Limit number of members to load
1420
     * @param int $memberoffset Offset members by this amount
1421
     * @param int $messagelimit Limit number of messages to load
1422
     * @param int $messageoffset Offset the messages
1423
     * @param bool $newestmessagesfirst Order messages by newest first
1424
     * @return stdClass
1425
     * @throws \moodle_exception if the messaging feature is disabled on the site.
1426
     */
1427
    public static function get_conversation(
1428
        int $userid,
1429
        int $conversationid,
1430
        bool $includecontactrequests = false,
1431
        bool $includeprivacyinfo = false,
1432
        int $memberlimit = 0,
1433
        int $memberoffset = 0,
1434
        int $messagelimit = 0,
1435
        int $messageoffset = 0,
1436
        bool $newestmessagesfirst = true
1437
    ) {
1438
        global $CFG, $DB, $USER;
1439
 
1440
        // All the standard BL checks.
1441
        if (empty($CFG->messaging)) {
1442
            throw new moodle_exception('disabled', 'message');
1443
        }
1444
 
1445
        $params = [
1446
            'userid' => $userid,
1447
            'conversationid' => $conversationid,
1448
            'includecontactrequests' => $includecontactrequests,
1449
            'includeprivacyinfo' => $includeprivacyinfo,
1450
            'memberlimit' => $memberlimit,
1451
            'memberoffset' => $memberoffset,
1452
            'messagelimit' => $messagelimit,
1453
            'messageoffset' => $messageoffset,
1454
            'newestmessagesfirst' => $newestmessagesfirst
1455
        ];
1456
        self::validate_parameters(self::get_conversation_parameters(), $params);
1457
 
1458
        $systemcontext = context_system::instance();
1459
        self::validate_context($systemcontext);
1460
 
1461
        $conversation = \core_message\api::get_conversation(
1462
            $params['userid'],
1463
            $params['conversationid'],
1464
            $params['includecontactrequests'],
1465
            $params['includeprivacyinfo'],
1466
            $params['memberlimit'],
1467
            $params['memberoffset'],
1468
            $params['messagelimit'],
1469
            $params['messageoffset'],
1470
            $params['newestmessagesfirst']
1471
        );
1472
 
1473
        if ($conversation) {
1474
            return $conversation;
1475
        } else {
1476
            // We have to throw an exception here because the external functions annoyingly
1477
            // don't accept null to be returned for a single structure.
1478
            throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1479
        }
1480
    }
1481
 
1482
    /**
1483
     * Get conversation returns.
1484
     *
1485
     * @return external_single_structure
1486
     */
1487
    public static function get_conversation_returns() {
1488
        return self::get_conversation_structure();
1489
    }
1490
 
1491
    /**
1492
     * Get conversation parameters.
1493
     *
1494
     * @return external_function_parameters
1495
     */
1496
    public static function get_conversation_between_users_parameters() {
1497
        return new external_function_parameters(
1498
            array(
1499
                'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing conversations for'),
1500
                'otheruserid' => new external_value(PARAM_INT, 'The other user id'),
1501
                'includecontactrequests' => new external_value(PARAM_BOOL, 'Include contact requests in the members'),
1502
                'includeprivacyinfo' => new external_value(PARAM_BOOL, 'Include privacy info in the members'),
1503
                'memberlimit' => new external_value(PARAM_INT, 'Limit for number of members', VALUE_DEFAULT, 0),
1504
                'memberoffset' => new external_value(PARAM_INT, 'Offset for member list', VALUE_DEFAULT, 0),
1505
                'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1506
                'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1507
                'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1508
            )
1509
        );
1510
    }
1511
 
1512
    /**
1513
     * Get a single conversation between users.
1514
     *
1515
     * @param int $userid The user id to get the conversation for
1516
     * @param int $otheruserid The other user id
1517
     * @param bool $includecontactrequests Should contact requests be included between members
1518
     * @param bool $includeprivacyinfo Should privacy info be included between members
1519
     * @param int $memberlimit Limit number of members to load
1520
     * @param int $memberoffset Offset members by this amount
1521
     * @param int $messagelimit Limit number of messages to load
1522
     * @param int $messageoffset Offset the messages
1523
     * @param bool $newestmessagesfirst Order messages by newest first
1524
     * @return stdClass
1525
     * @throws \moodle_exception if the messaging feature is disabled on the site.
1526
     */
1527
    public static function get_conversation_between_users(
1528
        int $userid,
1529
        int $otheruserid,
1530
        bool $includecontactrequests = false,
1531
        bool $includeprivacyinfo = false,
1532
        int $memberlimit = 0,
1533
        int $memberoffset = 0,
1534
        int $messagelimit = 0,
1535
        int $messageoffset = 0,
1536
        bool $newestmessagesfirst = true
1537
    ) {
1538
        global $CFG, $DB, $USER;
1539
 
1540
        // All the standard BL checks.
1541
        if (empty($CFG->messaging)) {
1542
            throw new moodle_exception('disabled', 'message');
1543
        }
1544
 
1545
        $params = [
1546
            'userid' => $userid,
1547
            'otheruserid' => $otheruserid,
1548
            'includecontactrequests' => $includecontactrequests,
1549
            'includeprivacyinfo' => $includeprivacyinfo,
1550
            'memberlimit' => $memberlimit,
1551
            'memberoffset' => $memberoffset,
1552
            'messagelimit' => $messagelimit,
1553
            'messageoffset' => $messageoffset,
1554
            'newestmessagesfirst' => $newestmessagesfirst
1555
        ];
1556
        self::validate_parameters(self::get_conversation_between_users_parameters(), $params);
1557
 
1558
        $systemcontext = context_system::instance();
1559
        self::validate_context($systemcontext);
1560
 
1561
        $conversationid = \core_message\api::get_conversation_between_users([$params['userid'], $params['otheruserid']]);
1562
        $conversation = null;
1563
 
1564
        if ($conversationid) {
1565
            $conversation = \core_message\api::get_conversation(
1566
                $params['userid'],
1567
                $conversationid,
1568
                $params['includecontactrequests'],
1569
                $params['includeprivacyinfo'],
1570
                $params['memberlimit'],
1571
                $params['memberoffset'],
1572
                $params['messagelimit'],
1573
                $params['messageoffset'],
1574
                $params['newestmessagesfirst']
1575
            );
1576
        }
1577
 
1578
        if ($conversation) {
1579
            return $conversation;
1580
        } else {
1581
            // We have to throw an exception here because the external functions annoyingly
1582
            // don't accept null to be returned for a single structure.
1583
            throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1584
        }
1585
    }
1586
 
1587
    /**
1588
     * Get conversation returns.
1589
     *
1590
     * @return external_single_structure
1591
     */
1592
    public static function get_conversation_between_users_returns() {
1593
        return self::get_conversation_structure(true);
1594
    }
1595
 
1596
    /**
1597
     * Get self-conversation parameters.
1598
     *
1599
     * @return external_function_parameters
1600
     */
1601
    public static function get_self_conversation_parameters() {
1602
        return new external_function_parameters(
1603
            array(
1604
                'userid' => new external_value(PARAM_INT, 'The id of the user who we are viewing self-conversations for'),
1605
                'messagelimit' => new external_value(PARAM_INT, 'Limit for number of messages', VALUE_DEFAULT, 100),
1606
                'messageoffset' => new external_value(PARAM_INT, 'Offset for messages list', VALUE_DEFAULT, 0),
1607
                'newestmessagesfirst' => new external_value(PARAM_BOOL, 'Order messages by newest first', VALUE_DEFAULT, true)
1608
            )
1609
        );
1610
    }
1611
 
1612
    /**
1613
     * Get a single self-conversation.
1614
     *
1615
     * @param int $userid The user id to get the self-conversation for
1616
     * @param int $messagelimit Limit number of messages to load
1617
     * @param int $messageoffset Offset the messages
1618
     * @param bool $newestmessagesfirst Order messages by newest first
1619
     * @return stdClass
1620
     * @throws \moodle_exception if the messaging feature is disabled on the site.
1621
     * @since Moodle 3.7
1622
     */
1623
    public static function get_self_conversation(
1624
        int $userid,
1625
        int $messagelimit = 0,
1626
        int $messageoffset = 0,
1627
        bool $newestmessagesfirst = true
1628
    ) {
1629
        global $CFG;
1630
 
1631
        // All the standard BL checks.
1632
        if (empty($CFG->messaging)) {
1633
            throw new moodle_exception('disabled', 'message');
1634
        }
1635
 
1636
        $params = [
1637
            'userid' => $userid,
1638
            'messagelimit' => $messagelimit,
1639
            'messageoffset' => $messageoffset,
1640
            'newestmessagesfirst' => $newestmessagesfirst
1641
        ];
1642
        self::validate_parameters(self::get_self_conversation_parameters(), $params);
1643
 
1644
        $systemcontext = context_system::instance();
1645
        self::validate_context($systemcontext);
1646
 
1647
        $conversation = \core_message\api::get_self_conversation($params['userid']);
1648
 
1649
        if ($conversation) {
1650
            $conversation = \core_message\api::get_conversation(
1651
                $params['userid'],
1652
                $conversation->id,
1653
                false,
1654
                false,
1655
                0,
1656
                0,
1657
                $params['messagelimit'],
1658
                $params['messageoffset'],
1659
                $params['newestmessagesfirst']
1660
            );
1661
        }
1662
 
1663
        if ($conversation) {
1664
            return $conversation;
1665
        } else {
1666
            // We have to throw an exception here because the external functions annoyingly
1667
            // don't accept null to be returned for a single structure.
1668
            throw new \moodle_exception('errorconversationdoesnotexist', 'message');
1669
        }
1670
    }
1671
 
1672
    /**
1673
     * Get conversation returns.
1674
     *
1675
     * @return external_single_structure
1676
     */
1677
    public static function get_self_conversation_returns() {
1678
        return self::get_conversation_structure();
1679
    }
1680
 
1681
    /**
1682
     * The conversation messages parameters.
1683
     *
1684
     * @return external_function_parameters
1685
     * @since 3.6
1686
     */
1687
    public static function get_conversation_messages_parameters() {
1688
        return new external_function_parameters(
1689
            array(
1690
                'currentuserid' => new external_value(PARAM_INT, 'The current user\'s id'),
1691
                'convid' => new external_value(PARAM_INT, 'The conversation id'),
1692
                'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1693
                'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0),
1694
                'newest' => new external_value(PARAM_BOOL, 'Newest first?', VALUE_DEFAULT, false),
1695
                'timefrom' => new external_value(PARAM_INT,
1696
                    'The timestamp from which the messages were created', VALUE_DEFAULT, 0),
1697
            )
1698
        );
1699
    }
1700
 
1701
    /**
1702
     * Get conversation messages.
1703
     *
1704
     * @param  int $currentuserid The current user's id.
1705
     * @param  int $convid The conversation id.
1706
     * @param  int $limitfrom Return a subset of records, starting at this point (optional).
1707
     * @param  int $limitnum Return a subset comprising this many records in total (optional, required if $limitfrom is set).
1708
     * @param  bool $newest True for getting first newest messages, false otherwise.
1709
     * @param  int  $timefrom The time from the conversation messages to get.
1710
     * @return array The messages and members who have sent some of these messages.
1711
     * @throws moodle_exception
1712
     * @since 3.6
1713
     */
1714
    public static function get_conversation_messages(int $currentuserid, int $convid, int $limitfrom = 0, int $limitnum = 0,
1715
                                                         bool $newest = false, int $timefrom = 0) {
1716
        global $CFG, $USER;
1717
 
1718
        // Check if messaging is enabled.
1719
        if (empty($CFG->messaging)) {
1720
            throw new moodle_exception('disabled', 'message');
1721
        }
1722
 
1723
        $systemcontext = context_system::instance();
1724
 
1725
        $params = array(
1726
            'currentuserid' => $currentuserid,
1727
            'convid' => $convid,
1728
            'limitfrom' => $limitfrom,
1729
            'limitnum' => $limitnum,
1730
            'newest' => $newest,
1731
            'timefrom' => $timefrom,
1732
        );
1733
        $params = self::validate_parameters(self::get_conversation_messages_parameters(), $params);
1734
        self::validate_context($systemcontext);
1735
 
1736
        if (($USER->id != $params['currentuserid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1737
            throw new moodle_exception('You do not have permission to perform this action.');
1738
        }
1739
 
1740
        // Check that the user belongs to the conversation.
1741
        if (!\core_message\api::is_user_in_conversation($params['currentuserid'], $params['convid'])) {
1742
            throw new moodle_exception('User is not part of conversation.');
1743
        }
1744
 
1745
        $sort = $newest ? 'timecreated DESC' : 'timecreated ASC';
1746
 
1747
        // We need to enforce a one second delay on messages to avoid race conditions of current
1748
        // messages still being sent.
1749
        //
1750
        // There is a chance that we could request messages before the current time's
1751
        // second has elapsed and while other messages are being sent in that same second. In which
1752
        // case those messages will be lost.
1753
        //
1754
        // Instead we ignore the current time in the result set to ensure that second is allowed to finish.
1755
        $timeto = empty($params['timefrom']) ? 0 : time() - 1;
1756
 
1757
        // No requesting messages from the current time, as stated above.
1758
        if ($params['timefrom'] == time()) {
1759
            $messages = [];
1760
        } else {
1761
            $messages = \core_message\api::get_conversation_messages(
1762
                $params['currentuserid'],
1763
                $params['convid'],
1764
                $params['limitfrom'],
1765
                $params['limitnum'],
1766
                $sort,
1767
                $params['timefrom'],
1768
                $timeto);
1769
        }
1770
 
1771
        return $messages;
1772
    }
1773
 
1774
    /**
1775
     * The messagearea messages return structure.
1776
     *
1777
     * @return external_single_structure
1778
     * @since 3.6
1779
     */
1780
    public static function get_conversation_messages_returns() {
1781
        return new external_single_structure(
1782
            array(
1783
                'id' => new external_value(PARAM_INT, 'The conversation id'),
1784
                'members' => new external_multiple_structure(
1785
                    self::get_conversation_member_structure()
1786
                ),
1787
                'messages' => new external_multiple_structure(
1788
                    self::get_conversation_message_structure()
1789
                ),
1790
            )
1791
        );
1792
    }
1793
 
1794
    /**
1795
     * The user contacts return parameters.
1796
     *
1797
     * @return external_function_parameters
1798
     */
1799
    public static function get_user_contacts_parameters() {
1800
        return new external_function_parameters(
1801
            array(
1802
                'userid' => new external_value(PARAM_INT, 'The id of the user who we retrieving the contacts for'),
1803
                'limitfrom' => new external_value(PARAM_INT, 'Limit from', VALUE_DEFAULT, 0),
1804
                'limitnum' => new external_value(PARAM_INT, 'Limit number', VALUE_DEFAULT, 0)
1805
            )
1806
        );
1807
    }
1808
 
1809
    /**
1810
     * Get user contacts.
1811
     *
1812
     * @param int $userid The id of the user who we are viewing conversations for
1813
     * @param int $limitfrom
1814
     * @param int $limitnum
1815
     * @return array
1816
     * @throws moodle_exception
1817
     */
1818
    public static function get_user_contacts(int $userid, int $limitfrom = 0, int $limitnum = 0) {
1819
        global $CFG, $USER;
1820
 
1821
        // Check if messaging is enabled.
1822
        if (empty($CFG->messaging)) {
1823
            throw new moodle_exception('disabled', 'message');
1824
        }
1825
 
1826
        $systemcontext = context_system::instance();
1827
 
1828
        $params = array(
1829
            'userid' => $userid,
1830
            'limitfrom' => $limitfrom,
1831
            'limitnum' => $limitnum
1832
        );
1833
        $params = self::validate_parameters(self::get_user_contacts_parameters(), $params);
1834
        self::validate_context($systemcontext);
1835
 
1836
        if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
1837
            throw new moodle_exception('You do not have permission to perform this action.');
1838
        }
1839
 
1840
        return \core_message\api::get_user_contacts($params['userid'], $params['limitfrom'], $params['limitnum']);
1841
    }
1842
 
1843
    /**
1844
     * The user contacts return structure.
1845
     *
1846
     * @return external_multiple_structure
1847
     */
1848
    public static function get_user_contacts_returns() {
1849
        return new external_multiple_structure(
1850
            self::get_conversation_member_structure()
1851
        );
1852
    }
1853
 
1854
    /**
1855
     * Search contacts parameters description.
1856
     *
1857
     * @return external_function_parameters
1858
     * @since Moodle 2.5
1859
     */
1860
    public static function search_contacts_parameters() {
1861
        return new external_function_parameters(
1862
            array(
1863
                'searchtext' => new external_value(PARAM_CLEAN, 'String the user\'s fullname has to match to be found'),
1864
                'onlymycourses' => new external_value(PARAM_BOOL, 'Limit search to the user\'s courses',
1865
                    VALUE_DEFAULT, false)
1866
            )
1867
        );
1868
    }
1869
 
1870
    /**
1871
     * Search contacts.
1872
     *
1873
     * @param string $searchtext query string.
1874
     * @param bool $onlymycourses limit the search to the user's courses only.
1875
     * @return \core_external\external_description
1876
     * @since Moodle 2.5
1877
     */
1878
    public static function search_contacts($searchtext, $onlymycourses = false) {
1879
        global $CFG, $USER, $PAGE;
1880
        require_once($CFG->dirroot . '/user/lib.php');
1881
 
1882
        // Check if messaging is enabled.
1883
        if (empty($CFG->messaging)) {
1884
            throw new moodle_exception('disabled', 'message');
1885
        }
1886
 
1887
        require_once($CFG->libdir . '/enrollib.php');
1888
 
1889
        $params = array('searchtext' => $searchtext, 'onlymycourses' => $onlymycourses);
1890
        $params = self::validate_parameters(self::search_contacts_parameters(), $params);
1891
 
1892
        // Extra validation, we do not allow empty queries.
1893
        if ($params['searchtext'] === '') {
1894
            throw new moodle_exception('querystringcannotbeempty');
1895
        }
1896
 
1897
        $courseids = array();
1898
        if ($params['onlymycourses']) {
1899
            $mycourses = enrol_get_my_courses(array('id'));
1900
            foreach ($mycourses as $mycourse) {
1901
                $courseids[] = $mycourse->id;
1902
            }
1903
        } else {
1904
            $courseids[] = SITEID;
1905
        }
1906
 
1907
        // Retrieving the users matching the query.
1908
        $users = message_search_users($courseids, $params['searchtext']);
1909
        $results = array();
1910
        foreach ($users as $user) {
1911
            $results[$user->id] = $user;
1912
        }
1913
 
1914
        // Reorganising information.
1915
        foreach ($results as &$user) {
1916
            $newuser = array(
1917
                'id' => $user->id,
1918
                'fullname' => fullname($user)
1919
            );
1920
 
1921
            // Avoid undefined property notice as phone not specified.
1922
            $user->phone1 = null;
1923
            $user->phone2 = null;
1924
 
1925
            $userpicture = new user_picture($user);
1926
            $userpicture->size = 1; // Size f1.
1927
            $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
1928
            $userpicture->size = 0; // Size f2.
1929
            $newuser['profileimageurlsmall'] = $userpicture->get_url($PAGE)->out(false);
1930
 
1931
            $user = $newuser;
1932
        }
1933
 
1934
        return $results;
1935
    }
1936
 
1937
    /**
1938
     * Search contacts return description.
1939
     *
1940
     * @return \core_external\external_description
1941
     * @since Moodle 2.5
1942
     */
1943
    public static function search_contacts_returns() {
1944
        return new external_multiple_structure(
1945
            new external_single_structure(
1946
                array(
1947
                    'id' => new external_value(PARAM_INT, 'User ID'),
1948
                    'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
1949
                    'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL),
1950
                    'profileimageurlsmall' => new external_value(PARAM_URL, 'Small user picture URL', VALUE_OPTIONAL)
1951
                )
1952
            ),
1953
            'List of contacts'
1954
        );
1955
    }
1956
 
1957
    /**
1958
     * Get messages parameters description.
1959
     *
1960
     * @return external_function_parameters
1961
     * @since 2.8
1962
     */
1963
    public static function get_messages_parameters() {
1964
        return new external_function_parameters(
1965
            array(
1966
                'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
1967
                'useridfrom' => new external_value(
1968
                    PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
1969
                    VALUE_DEFAULT, 0),
1970
                'type' => new external_value(
1971
                    PARAM_ALPHA, 'type of message to return, expected values are: notifications, conversations and both',
1972
                    VALUE_DEFAULT, 'both'),
1973
                'read' => new external_value(PARAM_INT, '1 for getting read messages, 0 for unread, 2 for both',
1974
                    VALUE_DEFAULT, 1),
1975
                'newestfirst' => new external_value(
1976
                    PARAM_BOOL, 'true for ordering by newest first, false for oldest first',
1977
                    VALUE_DEFAULT, true),
1978
                'limitfrom' => new external_value(PARAM_INT, 'limit from', VALUE_DEFAULT, 0),
1979
                'limitnum' => new external_value(PARAM_INT, 'limit number', VALUE_DEFAULT, 0)
1980
            )
1981
        );
1982
    }
1983
 
1984
    /**
1985
     * Get messages function implementation.
1986
     *
1987
     * @since  2.8
1988
     * @throws invalid_parameter_exception
1989
     * @throws moodle_exception
1990
     * @param  int      $useridto       the user id who received the message
1991
     * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
1992
     * @param  string   $type           type of message to return, expected values: notifications, conversations and both
1993
     * @param  int      $read           1 for getting read messages, 0 for unread, 2 for both
1994
     * @param  bool     $newestfirst    true for ordering by newest first, false for oldest first
1995
     * @param  int      $limitfrom      limit from
1996
     * @param  int      $limitnum       limit num
1997
     * @return \core_external\external_description
1998
     */
1999
    public static function get_messages($useridto, $useridfrom = 0, $type = 'both', $read = MESSAGE_GET_READ,
2000
                                        $newestfirst = true, $limitfrom = 0, $limitnum = 0) {
2001
        global $CFG, $USER, $PAGE;
2002
 
2003
        $warnings = array();
2004
 
2005
        $params = array(
2006
            'useridto' => $useridto,
2007
            'useridfrom' => $useridfrom,
2008
            'type' => $type,
2009
            'read' => $read,
2010
            'newestfirst' => $newestfirst,
2011
            'limitfrom' => $limitfrom,
2012
            'limitnum' => $limitnum
2013
        );
2014
 
2015
        $params = self::validate_parameters(self::get_messages_parameters(), $params);
2016
 
2017
        $context = context_system::instance();
2018
        self::validate_context($context);
2019
 
2020
        $useridto = $params['useridto'];
2021
        $useridfrom = $params['useridfrom'];
2022
        $type = $params['type'];
2023
        $read = $params['read'];
2024
        $newestfirst = $params['newestfirst'];
2025
        $limitfrom = $params['limitfrom'];
2026
        $limitnum = $params['limitnum'];
2027
 
2028
        $allowedvalues = array('notifications', 'conversations', 'both');
2029
        if (!in_array($type, $allowedvalues)) {
2030
            throw new invalid_parameter_exception('Invalid value for type parameter (value: ' . $type . '),' .
2031
                'allowed values are: ' . implode(',', $allowedvalues));
2032
        }
2033
 
2034
        // Check if private messaging between users is allowed.
2035
        if (empty($CFG->messaging)) {
2036
            // If we are retreiving only conversations, and messaging is disabled, throw an exception.
2037
            if ($type == "conversations") {
2038
                throw new moodle_exception('disabled', 'message');
2039
            }
2040
            if ($type == "both") {
2041
                $warning = array();
2042
                $warning['item'] = 'message';
2043
                $warning['itemid'] = $USER->id;
2044
                $warning['warningcode'] = '1';
2045
                $warning['message'] = 'Private messages (conversations) are not enabled in this site.
2046
                    Only notifications will be returned';
2047
                $warnings[] = $warning;
2048
            }
2049
        }
2050
 
2051
        if (!empty($useridto)) {
2052
            if (core_user::is_real_user($useridto)) {
2053
                $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2054
            } else {
2055
                throw new moodle_exception('invaliduser');
2056
            }
2057
        }
2058
 
2059
        if (!empty($useridfrom)) {
2060
            // We use get_user here because the from user can be the noreply or support user.
2061
            $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2062
        }
2063
 
2064
        // Check if the current user is the sender/receiver or just a privileged user.
2065
        if ($useridto != $USER->id and $useridfrom != $USER->id and
2066
             !has_capability('moodle/site:readallmessages', $context)) {
2067
            throw new moodle_exception('accessdenied', 'admin');
2068
        }
2069
 
2070
        // Which type of messages to retrieve.
2071
        $notifications = -1;
2072
        if ($type != 'both') {
2073
            $notifications = ($type == 'notifications') ? 1 : 0;
2074
        }
2075
 
2076
        $orderdirection = $newestfirst ? 'DESC' : 'ASC';
2077
        $sort = "mr.timecreated $orderdirection";
2078
 
2079
        if ($messages = message_get_messages($useridto, $useridfrom, $notifications, $read, $sort, $limitfrom, $limitnum)) {
2080
            $canviewfullname = has_capability('moodle/site:viewfullnames', $context);
2081
 
2082
            // In some cases, we don't need to get the to/from user objects from the sql query.
2083
            $userfromfullname = '';
2084
            $usertofullname = '';
2085
 
2086
            // In this case, the useridto field is not empty, so we can get the user destinatary fullname from there.
2087
            if (!empty($useridto)) {
2088
                $usertofullname = fullname($userto, $canviewfullname);
2089
                // The user from may or may not be filled.
2090
                if (!empty($useridfrom)) {
2091
                    $userfromfullname = fullname($userfrom, $canviewfullname);
2092
                }
2093
            } else {
2094
                // If the useridto field is empty, the useridfrom must be filled.
2095
                $userfromfullname = fullname($userfrom, $canviewfullname);
2096
            }
2097
            foreach ($messages as $mid => $message) {
2098
 
2099
                if (!$message->notification) {
2100
                    // Do not return deleted messages.
2101
                    if (($useridto == $USER->id and $message->timeusertodeleted) or
2102
                        ($useridfrom == $USER->id and $message->timeuserfromdeleted)) {
2103
                        unset($messages[$mid]);
2104
                        continue;
2105
                    }
2106
                } else {
2107
                    // Return iconurl for notifications.
2108
                    if (!isset($output)) {
2109
                        $output = $PAGE->get_renderer('core');
2110
                    }
2111
 
2112
                    if (!empty($message->component) && substr($message->component, 0, 4) == 'mod_') {
2113
                        $iconurl = $output->image_url('monologo', $message->component);
2114
                    } else {
2115
                        $iconurl = $output->image_url('i/marker', 'core');
2116
                    }
2117
 
2118
                    $message->iconurl = clean_param($iconurl->out(), PARAM_URL);
2119
                }
2120
 
2121
                // We need to get the user from the query.
2122
                if (empty($userfromfullname)) {
2123
                    // Check for non-reply and support users.
2124
                    if (core_user::is_real_user($message->useridfrom)) {
2125
                        $user = new stdClass();
2126
                        $user = username_load_fields_from_object($user, $message, 'userfrom');
2127
                        $message->userfromfullname = fullname($user, $canviewfullname);
2128
                    } else {
2129
                        $user = core_user::get_user($message->useridfrom);
2130
                        $message->userfromfullname = fullname($user, $canviewfullname);
2131
                    }
2132
                } else {
2133
                    $message->userfromfullname = $userfromfullname;
2134
                }
2135
 
2136
                // We need to get the user from the query.
2137
                if (empty($usertofullname)) {
2138
                    $user = new stdClass();
2139
                    $user = username_load_fields_from_object($user, $message, 'userto');
2140
                    $message->usertofullname = fullname($user, $canviewfullname);
2141
                } else {
2142
                    $message->usertofullname = $usertofullname;
2143
                }
2144
 
2145
                // Clean subject of html.
2146
                $message->subject = clean_param($message->subject, PARAM_TEXT);
2147
                $message->text = message_format_message_text($message);
2148
                $messages[$mid] = (array) $message;
2149
            }
2150
        }
2151
 
2152
        $results = array(
2153
            'messages' => $messages,
2154
            'warnings' => $warnings
2155
        );
2156
 
2157
        return $results;
2158
    }
2159
 
2160
    /**
2161
     * Get messages return description.
2162
     *
2163
     * @return external_single_structure
2164
     * @since 2.8
2165
     */
2166
    public static function get_messages_returns() {
2167
        return new external_single_structure(
2168
            array(
2169
                'messages' => new external_multiple_structure(
2170
                    new external_single_structure(
2171
                        array(
2172
                            'id' => new external_value(PARAM_INT, 'Message id'),
2173
                            'useridfrom' => new external_value(PARAM_INT, 'User from id'),
2174
                            'useridto' => new external_value(PARAM_INT, 'User to id'),
2175
                            'subject' => new external_value(PARAM_TEXT, 'The message subject'),
2176
                            'text' => new external_value(PARAM_RAW, 'The message text formated'),
2177
                            'fullmessage' => new external_value(PARAM_RAW, 'The message'),
2178
                            'fullmessageformat' => new external_format_value('fullmessage'),
2179
                            'fullmessagehtml' => new external_value(PARAM_RAW, 'The message in html'),
2180
                            'smallmessage' => new external_value(PARAM_RAW, 'The shorten message'),
2181
                            'notification' => new external_value(PARAM_INT, 'Is a notification?'),
2182
                            'contexturl' => new external_value(PARAM_RAW, 'Context URL'),
2183
                            'contexturlname' => new external_value(PARAM_TEXT, 'Context URL link name'),
2184
                            'timecreated' => new external_value(PARAM_INT, 'Time created'),
2185
                            'timeread' => new external_value(PARAM_INT, 'Time read'),
2186
                            'usertofullname' => new external_value(PARAM_TEXT, 'User to full name'),
2187
                            'userfromfullname' => new external_value(PARAM_TEXT, 'User from full name'),
2188
                            'component' => new external_value(PARAM_TEXT, 'The component that generated the notification',
2189
                                VALUE_OPTIONAL),
2190
                            'eventtype' => new external_value(PARAM_TEXT, 'The type of notification', VALUE_OPTIONAL),
2191
                            'customdata' => new external_value(PARAM_RAW, 'Custom data to be passed to the message processor.
2192
                                The data here is serialised using json_encode().', VALUE_OPTIONAL),
2193
                            'iconurl' => new external_value(PARAM_URL, 'URL for icon, only for notifications.', VALUE_OPTIONAL),
2194
                        ), 'message'
2195
                    )
2196
                ),
2197
                'warnings' => new external_warnings()
2198
            )
2199
        );
2200
    }
2201
 
2202
    /**
2203
     * Mark all notifications as read parameters description.
2204
     *
2205
     * @return external_function_parameters
2206
     * @since 3.2
2207
     */
2208
    public static function mark_all_notifications_as_read_parameters() {
2209
        return new external_function_parameters(
2210
            array(
2211
                'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2212
                'useridfrom' => new external_value(
2213
                    PARAM_INT, 'the user id who send the message, 0 for any user. -10 or -20 for no-reply or support user',
2214
                    VALUE_DEFAULT, 0),
2215
                'timecreatedto' => new external_value(
2216
                    PARAM_INT, 'mark messages created before this time as read, 0 for all messages',
2217
                    VALUE_DEFAULT, 0),
2218
            )
2219
        );
2220
    }
2221
 
2222
    /**
2223
     * Mark all notifications as read function.
2224
     *
2225
     * @since  3.2
2226
     * @throws invalid_parameter_exception
2227
     * @throws moodle_exception
2228
     * @param  int      $useridto       the user id who received the message
2229
     * @param  int      $useridfrom     the user id who send the message. -10 or -20 for no-reply or support user
2230
     * @param  int      $timecreatedto  mark message created before this time as read, 0 for all messages
2231
     * @return \core_external\external_description
2232
     */
2233
    public static function mark_all_notifications_as_read($useridto, $useridfrom, $timecreatedto = 0) {
2234
        global $USER;
2235
 
2236
        $params = self::validate_parameters(
2237
            self::mark_all_notifications_as_read_parameters(),
2238
            array(
2239
                'useridto' => $useridto,
2240
                'useridfrom' => $useridfrom,
2241
                'timecreatedto' => $timecreatedto,
2242
            )
2243
        );
2244
 
2245
        $context = context_system::instance();
2246
        self::validate_context($context);
2247
 
2248
        $useridto = $params['useridto'];
2249
        $useridfrom = $params['useridfrom'];
2250
        $timecreatedto = $params['timecreatedto'];
2251
 
2252
        if (!empty($useridto)) {
2253
            if (core_user::is_real_user($useridto)) {
2254
                $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2255
            } else {
2256
                throw new moodle_exception('invaliduser');
2257
            }
2258
        }
2259
 
2260
        if (!empty($useridfrom)) {
2261
            // We use get_user here because the from user can be the noreply or support user.
2262
            $userfrom = core_user::get_user($useridfrom, '*', MUST_EXIST);
2263
        }
2264
 
2265
        // Check if the current user is the sender/receiver or just a privileged user.
2266
        if ($useridto != $USER->id and $useridfrom != $USER->id and
2267
            // The deleteanymessage cap seems more reasonable here than readallmessages.
2268
             !has_capability('moodle/site:deleteanymessage', $context)) {
2269
            throw new moodle_exception('accessdenied', 'admin');
2270
        }
2271
 
2272
        \core_message\api::mark_all_notifications_as_read($useridto, $useridfrom, $timecreatedto);
2273
 
2274
        return true;
2275
    }
2276
 
2277
    /**
2278
     * Mark all notifications as read return description.
2279
     *
2280
     * @return external_single_structure
2281
     * @since 3.2
2282
     */
2283
    public static function mark_all_notifications_as_read_returns() {
2284
        return new external_value(PARAM_BOOL, 'True if the messages were marked read, false otherwise');
2285
    }
2286
 
2287
    /**
2288
     * Get unread conversations count parameters description.
2289
     *
2290
     * @return external_function_parameters
2291
     * @since 3.2
2292
     */
2293
    public static function get_unread_conversations_count_parameters() {
2294
        return new external_function_parameters(
2295
            array(
2296
                'useridto' => new external_value(PARAM_INT, 'the user id who received the message, 0 for any user', VALUE_REQUIRED),
2297
            )
2298
        );
2299
    }
2300
 
2301
    /**
2302
     * Get unread messages count function.
2303
     *
2304
     * @since  3.2
2305
     * @throws invalid_parameter_exception
2306
     * @throws moodle_exception
2307
     * @param  int      $useridto       the user id who received the message
2308
     * @return \core_external\external_description
2309
     */
2310
    public static function get_unread_conversations_count($useridto) {
2311
        global $USER, $CFG;
2312
 
2313
        // Check if messaging is enabled.
2314
        if (empty($CFG->messaging)) {
2315
            throw new moodle_exception('disabled', 'message');
2316
        }
2317
 
2318
        $params = self::validate_parameters(
2319
            self::get_unread_conversations_count_parameters(),
2320
            array('useridto' => $useridto)
2321
        );
2322
 
2323
        $context = context_system::instance();
2324
        self::validate_context($context);
2325
 
2326
        $useridto = $params['useridto'];
2327
 
2328
        if (!empty($useridto)) {
2329
            if (core_user::is_real_user($useridto)) {
2330
                $userto = core_user::get_user($useridto, '*', MUST_EXIST);
2331
            } else {
2332
                throw new moodle_exception('invaliduser');
2333
            }
2334
        } else {
2335
            $useridto = $USER->id;
2336
        }
2337
 
2338
        // Check if the current user is the receiver or just a privileged user.
2339
        if ($useridto != $USER->id and !has_capability('moodle/site:readallmessages', $context)) {
2340
            throw new moodle_exception('accessdenied', 'admin');
2341
        }
2342
 
2343
        return \core_message\api::count_unread_conversations($userto);
2344
    }
2345
 
2346
    /**
2347
     * Get unread conversations count return description.
2348
     *
2349
     * @return external_single_structure
2350
     * @since 3.2
2351
     */
2352
    public static function get_unread_conversations_count_returns() {
2353
        return new external_value(PARAM_INT, 'The count of unread messages for the user');
2354
    }
2355
 
2356
    /**
2357
     * Get blocked users parameters description.
2358
     *
2359
     * @return external_function_parameters
2360
     * @since 2.9
2361
     */
2362
    public static function get_blocked_users_parameters() {
2363
        return new external_function_parameters(
2364
            array(
2365
                'userid' => new external_value(PARAM_INT,
2366
                                'the user whose blocked users we want to retrieve',
2367
                                VALUE_REQUIRED),
2368
            )
2369
        );
2370
    }
2371
 
2372
    /**
2373
     * Retrieve a list of users blocked
2374
     *
2375
     * @param  int $userid the user whose blocked users we want to retrieve
2376
     * @return \core_external\external_description
2377
     * @since 2.9
2378
     */
2379
    public static function get_blocked_users($userid) {
2380
        global $CFG, $USER, $PAGE;
2381
 
2382
        // Warnings array, it can be empty at the end but is mandatory.
2383
        $warnings = array();
2384
 
2385
        // Validate params.
2386
        $params = array(
2387
            'userid' => $userid
2388
        );
2389
        $params = self::validate_parameters(self::get_blocked_users_parameters(), $params);
2390
        $userid = $params['userid'];
2391
 
2392
        // Validate context.
2393
        $context = context_system::instance();
2394
        self::validate_context($context);
2395
 
2396
        // Check if private messaging between users is allowed.
2397
        if (empty($CFG->messaging)) {
2398
            throw new moodle_exception('disabled', 'message');
2399
        }
2400
 
2401
        $user = core_user::get_user($userid, '*', MUST_EXIST);
2402
        core_user::require_active_user($user);
2403
 
2404
        // Check if we have permissions for retrieve the information.
2405
        $capability = 'moodle/site:manageallmessaging';
2406
        if (($USER->id != $userid) && !has_capability($capability, $context)) {
2407
            throw new required_capability_exception($context, $capability, 'nopermissions', '');
2408
        }
2409
 
2410
        // Now, we can get safely all the blocked users.
2411
        $users = \core_message\api::get_blocked_users($user->id);
2412
 
2413
        $blockedusers = array();
2414
        foreach ($users as $user) {
2415
            $newuser = array(
2416
                'id' => $user->id,
2417
                'fullname' => fullname($user),
2418
            );
2419
 
2420
            $userpicture = new user_picture($user);
2421
            $userpicture->size = 1; // Size f1.
2422
            $newuser['profileimageurl'] = $userpicture->get_url($PAGE)->out(false);
2423
 
2424
            $blockedusers[] = $newuser;
2425
        }
2426
 
2427
        $results = array(
2428
            'users' => $blockedusers,
2429
            'warnings' => $warnings
2430
        );
2431
        return $results;
2432
    }
2433
 
2434
    /**
2435
     * Get blocked users return description.
2436
     *
2437
     * @return external_single_structure
2438
     * @since 2.9
2439
     */
2440
    public static function get_blocked_users_returns() {
2441
        return new external_single_structure(
2442
            array(
2443
                'users' => new external_multiple_structure(
2444
                    new external_single_structure(
2445
                        array(
2446
                            'id' => new external_value(PARAM_INT, 'User ID'),
2447
                            'fullname' => new external_value(PARAM_NOTAGS, 'User full name'),
2448
                            'profileimageurl' => new external_value(PARAM_URL, 'User picture URL', VALUE_OPTIONAL)
2449
                        )
2450
                    ),
2451
                    'List of blocked users'
2452
                ),
2453
                'warnings' => new external_warnings()
2454
            )
2455
        );
2456
    }
2457
 
2458
    /**
2459
     * Returns description of method parameters
2460
     *
2461
     * @return external_function_parameters
2462
     * @since 2.9
2463
     */
2464
    public static function mark_message_read_parameters() {
2465
        return new external_function_parameters(
2466
            array(
2467
                'messageid' => new external_value(PARAM_INT, 'id of the message in the messages table'),
2468
                'timeread' => new external_value(PARAM_INT, 'timestamp for when the message should be marked read',
2469
                    VALUE_DEFAULT, 0)
2470
            )
2471
        );
2472
    }
2473
 
2474
    /**
2475
     * Mark a single message as read, trigger message_viewed event
2476
     *
2477
     * @param  int $messageid id of the message (in the message table)
2478
     * @param  int $timeread timestamp for when the message should be marked read
2479
     * @return \core_external\external_description
2480
     * @throws invalid_parameter_exception
2481
     * @throws moodle_exception
2482
     * @since 2.9
2483
     */
2484
    public static function mark_message_read($messageid, $timeread) {
2485
        global $CFG, $DB, $USER;
2486
 
2487
        // Check if private messaging between users is allowed.
2488
        if (empty($CFG->messaging)) {
2489
            throw new moodle_exception('disabled', 'message');
2490
        }
2491
 
2492
        // Warnings array, it can be empty at the end but is mandatory.
2493
        $warnings = array();
2494
 
2495
        // Validate params.
2496
        $params = array(
2497
            'messageid' => $messageid,
2498
            'timeread' => $timeread
2499
        );
2500
        $params = self::validate_parameters(self::mark_message_read_parameters(), $params);
2501
 
2502
        if (empty($params['timeread'])) {
2503
            $timeread = time();
2504
        } else {
2505
            $timeread = $params['timeread'];
2506
        }
2507
 
2508
        // Validate context.
2509
        $context = context_system::instance();
2510
        self::validate_context($context);
2511
 
2512
        $sql = "SELECT m.*, mcm.userid as useridto
2513
                  FROM {messages} m
2514
            INNER JOIN {message_conversations} mc
2515
                    ON m.conversationid = mc.id
2516
            INNER JOIN {message_conversation_members} mcm
2517
                    ON mcm.conversationid = mc.id
2518
             LEFT JOIN {message_user_actions} mua
2519
                    ON (mua.messageid = m.id AND mua.userid = ? AND mua.action = ?)
2520
                 WHERE mua.id is NULL
2521
                   AND mcm.userid != m.useridfrom
2522
                   AND m.id = ?";
2523
        $messageparams = [];
2524
        $messageparams[] = $USER->id;
2525
        $messageparams[] = \core_message\api::MESSAGE_ACTION_READ;
2526
        $messageparams[] = $params['messageid'];
2527
        $message = $DB->get_record_sql($sql, $messageparams, MUST_EXIST);
2528
 
2529
        if ($message->useridto != $USER->id) {
2530
            throw new invalid_parameter_exception('Invalid messageid, you don\'t have permissions to mark this message as read');
2531
        }
2532
 
2533
        \core_message\api::mark_message_as_read($USER->id, $message, $timeread);
2534
 
2535
        $results = array(
2536
            'messageid' => $message->id,
2537
            'warnings' => $warnings
2538
        );
2539
        return $results;
2540
    }
2541
 
2542
    /**
2543
     * Returns description of method result value
2544
     *
2545
     * @return \core_external\external_description
2546
     * @since 2.9
2547
     */
2548
    public static function mark_message_read_returns() {
2549
        return new external_single_structure(
2550
            array(
2551
                'messageid' => new external_value(PARAM_INT, 'the id of the message in the messages table'),
2552
                'warnings' => new external_warnings()
2553
            )
2554
        );
2555
    }
2556
 
2557
    /**
2558
     * Returns description of method parameters
2559
     *
2560
     * @return external_function_parameters
2561
     */
2562
    public static function mark_notification_read_parameters() {
2563
        return new external_function_parameters(
2564
            array(
2565
                'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2566
                'timeread' => new external_value(PARAM_INT, 'timestamp for when the notification should be marked read',
2567
                    VALUE_DEFAULT, 0)
2568
            )
2569
        );
2570
    }
2571
 
2572
    /**
2573
     * Mark a single notification as read.
2574
     *
2575
     * This will trigger a 'notification_viewed' event.
2576
     *
2577
     * @param int $notificationid id of the notification
2578
     * @param int $timeread timestamp for when the notification should be marked read
2579
     * @return \core_external\external_description
2580
     * @throws invalid_parameter_exception
2581
     * @throws moodle_exception
2582
     */
2583
    public static function mark_notification_read($notificationid, $timeread) {
2584
        global $CFG, $DB, $USER;
2585
 
2586
        // Warnings array, it can be empty at the end but is mandatory.
2587
        $warnings = array();
2588
 
2589
        // Validate params.
2590
        $params = array(
2591
            'notificationid' => $notificationid,
2592
            'timeread' => $timeread
2593
        );
2594
        $params = self::validate_parameters(self::mark_notification_read_parameters(), $params);
2595
 
2596
        if (empty($params['timeread'])) {
2597
            $timeread = time();
2598
        } else {
2599
            $timeread = $params['timeread'];
2600
        }
2601
 
2602
        // Validate context.
2603
        $context = context_system::instance();
2604
        self::validate_context($context);
2605
 
2606
        $notification = $DB->get_record('notifications', ['id' => $params['notificationid']], '*', MUST_EXIST);
2607
 
2608
        if ($notification->useridto != $USER->id) {
2609
            throw new invalid_parameter_exception('Invalid notificationid, you don\'t have permissions to mark this ' .
2610
                'notification as read');
2611
        }
2612
 
2613
        \core_message\api::mark_notification_as_read($notification, $timeread);
2614
 
2615
        $results = array(
2616
            'notificationid' => $notification->id,
2617
            'warnings' => $warnings
2618
        );
2619
 
2620
        return $results;
2621
    }
2622
 
2623
    /**
2624
     * Returns description of method result value
2625
     *
2626
     * @return \core_external\external_description
2627
     */
2628
    public static function mark_notification_read_returns() {
2629
        return new external_single_structure(
2630
            array(
2631
                'notificationid' => new external_value(PARAM_INT, 'id of the notification'),
2632
                'warnings' => new external_warnings()
2633
            )
2634
        );
2635
    }
2636
 
2637
    /**
2638
     * Mark all conversation messages as read parameters description.
2639
     *
2640
     * @return external_function_parameters
2641
     * @since 3.6
2642
     */
2643
    public static function mark_all_conversation_messages_as_read_parameters() {
2644
        return new external_function_parameters(
2645
            array(
2646
                'userid' => new external_value(PARAM_INT, 'The user id who who we are marking the messages as read for'),
2647
                'conversationid' =>
2648
                    new external_value(PARAM_INT, 'The conversation id who who we are marking the messages as read for')
2649
            )
2650
        );
2651
    }
2652
 
2653
    /**
2654
     * Mark all conversation messages as read function.
2655
     *
2656
     * @param int $userid The user id of who we want to delete the conversation for
2657
     * @param int $conversationid The id of the conversations
2658
     * @since 3.6
2659
     */
2660
    public static function mark_all_conversation_messages_as_read(int $userid, int $conversationid) {
2661
        global $CFG;
2662
 
2663
        // Check if messaging is enabled.
2664
        if (empty($CFG->messaging)) {
2665
            throw new moodle_exception('disabled', 'message');
2666
        }
2667
 
2668
        $params = array(
2669
            'userid' => $userid,
2670
            'conversationid' => $conversationid,
2671
        );
2672
        $params = self::validate_parameters(self::mark_all_conversation_messages_as_read_parameters(), $params);
2673
 
2674
        $context = context_system::instance();
2675
        self::validate_context($context);
2676
 
2677
        $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2678
        core_user::require_active_user($user);
2679
 
2680
        if (\core_message\api::can_mark_all_messages_as_read($params['userid'], $params['conversationid'])) {
2681
            \core_message\api::mark_all_messages_as_read($params['userid'], $params['conversationid']);
2682
        } else {
2683
            throw new moodle_exception('accessdenied', 'admin');
2684
        }
2685
    }
2686
 
2687
    /**
2688
     * Mark all conversation messages as read return description.
2689
     *
2690
     * @return external_warnings
2691
     * @since 3.6
2692
     */
2693
    public static function mark_all_conversation_messages_as_read_returns() {
2694
        return null;
2695
    }
2696
 
2697
    /**
2698
     * Returns description of method parameters.
2699
     *
2700
     * @return external_function_parameters
2701
     * @since 3.6
2702
     */
2703
    public static function delete_conversations_by_id_parameters() {
2704
        return new external_function_parameters(
2705
            array(
2706
                'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the conversation for'),
2707
                'conversationids' => new external_multiple_structure(
2708
                    new external_value(PARAM_INT, 'The id of the conversation'),
2709
                    'List of conversation IDs'
2710
                ),
2711
            )
2712
        );
2713
    }
2714
 
2715
    /**
2716
     * Deletes a conversation.
2717
     *
2718
     * @param int $userid The user id of who we want to delete the conversation for
2719
     * @param int[] $conversationids The ids of the conversations
2720
     * @return array
2721
     * @throws moodle_exception
2722
     * @since 3.6
2723
     */
2724
    public static function delete_conversations_by_id($userid, array $conversationids) {
2725
        global $CFG;
2726
 
2727
        // Check if private messaging between users is allowed.
2728
        if (empty($CFG->messaging)) {
2729
            throw new moodle_exception('disabled', 'message');
2730
        }
2731
 
2732
        // Validate params.
2733
        $params = [
2734
            'userid' => $userid,
2735
            'conversationids' => $conversationids,
2736
        ];
2737
        $params = self::validate_parameters(self::delete_conversations_by_id_parameters(), $params);
2738
 
2739
        // Validate context.
2740
        $context = context_system::instance();
2741
        self::validate_context($context);
2742
 
2743
        $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2744
        core_user::require_active_user($user);
2745
 
2746
        foreach ($params['conversationids'] as $conversationid) {
2747
            if (\core_message\api::can_delete_conversation($user->id, $conversationid)) {
2748
                \core_message\api::delete_conversation_by_id($user->id, $conversationid);
2749
            } else {
2750
                throw new moodle_exception("You do not have permission to delete the conversation '$conversationid'");
2751
            }
2752
        }
2753
 
2754
        return [];
2755
    }
2756
 
2757
    /**
2758
     * Returns description of method result value.
2759
     *
2760
     * @return \core_external\external_description
2761
     * @since 3.6
2762
     */
2763
    public static function delete_conversations_by_id_returns() {
2764
        return new external_warnings();
2765
    }
2766
 
2767
    /**
2768
     * Returns description of method parameters
2769
     *
2770
     * @return external_function_parameters
2771
     * @since 3.1
2772
     */
2773
    public static function delete_message_parameters() {
2774
        return new external_function_parameters(
2775
            array(
2776
                'messageid' => new external_value(PARAM_INT, 'The message id'),
2777
                'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for'),
2778
                'read' => new external_value(PARAM_BOOL, 'If is a message read', VALUE_DEFAULT, true)
2779
            )
2780
        );
2781
    }
2782
 
2783
    /**
2784
     * Deletes a message
2785
     *
2786
     * @param  int $messageid the message id
2787
     * @param  int $userid the user id of who we want to delete the message for
2788
     * @param  bool $read if is a message read (default to true)
2789
     * @return \core_external\external_description
2790
     * @throws moodle_exception
2791
     * @since 3.1
2792
     */
2793
    public static function delete_message($messageid, $userid, $read = true) {
2794
        global $CFG;
2795
 
2796
        // Check if private messaging between users is allowed.
2797
        if (empty($CFG->messaging)) {
2798
            throw new moodle_exception('disabled', 'message');
2799
        }
2800
 
2801
        // Warnings array, it can be empty at the end but is mandatory.
2802
        $warnings = array();
2803
 
2804
        // Validate params.
2805
        $params = array(
2806
            'messageid' => $messageid,
2807
            'userid' => $userid,
2808
            'read' => $read
2809
        );
2810
        $params = self::validate_parameters(self::delete_message_parameters(), $params);
2811
 
2812
        // Validate context.
2813
        $context = context_system::instance();
2814
        self::validate_context($context);
2815
 
2816
        $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2817
        core_user::require_active_user($user);
2818
 
2819
        if (\core_message\api::can_delete_message($user->id, $params['messageid'])) {
2820
            $status = \core_message\api::delete_message($user->id, $params['messageid']);
2821
        } else {
2822
            throw new moodle_exception('You do not have permission to delete this message');
2823
        }
2824
 
2825
        $results = array(
2826
            'status' => $status,
2827
            'warnings' => $warnings
2828
        );
2829
        return $results;
2830
    }
2831
 
2832
    /**
2833
     * Returns description of method result value
2834
     *
2835
     * @return \core_external\external_description
2836
     * @since 3.1
2837
     */
2838
    public static function delete_message_returns() {
2839
        return new external_single_structure(
2840
            array(
2841
                'status' => new external_value(PARAM_BOOL, 'True if the message was deleted, false otherwise'),
2842
                'warnings' => new external_warnings()
2843
            )
2844
        );
2845
    }
2846
 
2847
    /**
2848
     * Returns description of method parameters
2849
     *
2850
     * @return external_function_parameters
2851
     * @since 3.2
2852
     */
2853
    public static function message_processor_config_form_parameters() {
2854
        return new external_function_parameters(
2855
            array(
2856
                'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_REQUIRED),
2857
                'name' => new external_value(PARAM_SAFEDIR, 'The name of the message processor'),
2858
                'formvalues' => new external_multiple_structure(
2859
                    new external_single_structure(
2860
                        array(
2861
                            'name' => new external_value(PARAM_TEXT, 'name of the form element', VALUE_REQUIRED),
2862
                            'value' => new external_value(PARAM_RAW, 'value of the form element', VALUE_REQUIRED),
2863
                        )
2864
                    ),
2865
                    'Config form values',
2866
                    VALUE_REQUIRED
2867
                ),
2868
            )
2869
        );
2870
    }
2871
 
2872
    /**
2873
     * Processes a message processor config form.
2874
     *
2875
     * @param  int $userid the user id
2876
     * @param  string $name the name of the processor
2877
     * @param  array $formvalues the form values
2878
     * @return \core_external\external_description
2879
     * @throws moodle_exception
2880
     * @since 3.2
2881
     */
2882
    public static function message_processor_config_form($userid, $name, $formvalues) {
2883
        global $USER, $CFG;
2884
 
2885
        $params = self::validate_parameters(
2886
            self::message_processor_config_form_parameters(),
2887
            array(
2888
                'userid' => $userid,
2889
                'name' => $name,
2890
                'formvalues' => $formvalues,
2891
            )
2892
        );
2893
 
2894
        $user = self::validate_preferences_permissions($params['userid']);
2895
 
2896
        $processor = get_message_processor($params['name']);
2897
        $preferences = [];
2898
        $form = new stdClass();
2899
 
2900
        foreach ($params['formvalues'] as $formvalue) {
2901
            // Curly braces to ensure interpretation is consistent between
2902
            // php 5 and php 7.
2903
            $form->{$formvalue['name']} = $formvalue['value'];
2904
        }
2905
 
2906
        $processor->process_form($form, $preferences);
2907
 
2908
        if (!empty($preferences)) {
2909
            set_user_preferences($preferences, $params['userid']);
2910
        }
2911
    }
2912
 
2913
    /**
2914
     * Returns description of method result value
2915
     *
2916
     * @return \core_external\external_description
2917
     * @since 3.2
2918
     */
2919
    public static function message_processor_config_form_returns() {
2920
        return null;
2921
    }
2922
 
2923
    /**
2924
     * Returns description of method parameters
2925
     *
2926
     * @return external_function_parameters
2927
     * @since 3.2
2928
     */
2929
    public static function get_message_processor_parameters() {
2930
        return new external_function_parameters(
2931
            array(
2932
                'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user'),
2933
                'name' => new external_value(PARAM_SAFEDIR, 'The name of the message processor', VALUE_REQUIRED),
2934
            )
2935
        );
2936
    }
2937
 
2938
    /**
2939
     * Get a message processor.
2940
     *
2941
     * @param int $userid
2942
     * @param string $name the name of the processor
2943
     * @return \core_external\external_description
2944
     * @throws moodle_exception
2945
     * @since 3.2
2946
     */
2947
    public static function get_message_processor($userid, $name) {
2948
        global $USER, $PAGE, $CFG;
2949
 
2950
        // Check if messaging is enabled.
2951
        if (empty($CFG->messaging)) {
2952
            throw new moodle_exception('disabled', 'message');
2953
        }
2954
 
2955
        $params = self::validate_parameters(
2956
            self::get_message_processor_parameters(),
2957
            array(
2958
                'userid' => $userid,
2959
                'name' => $name,
2960
            )
2961
        );
2962
 
2963
        if (empty($params['userid'])) {
2964
            $params['userid'] = $USER->id;
2965
        }
2966
 
2967
        $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
2968
        core_user::require_active_user($user);
2969
        self::validate_context(context_user::instance($params['userid']));
2970
 
2971
        $processor = get_message_processor($params['name']);
2972
 
2973
        $processoroutput = new \core_message\output\processor($processor, $user);
2974
        $renderer = $PAGE->get_renderer('core_message');
2975
 
2976
        return $processoroutput->export_for_template($renderer);
2977
    }
2978
 
2979
    /**
2980
     * Returns description of method result value
2981
     *
2982
     * @return \core_external\external_description
2983
     * @since 3.2
2984
     */
2985
    public static function get_message_processor_returns() {
2986
        return new external_function_parameters(
2987
            array(
2988
                'systemconfigured' => new external_value(PARAM_BOOL, 'Site configuration status'),
2989
                'userconfigured' => new external_value(PARAM_BOOL, 'The user configuration status'),
2990
            )
2991
        );
2992
    }
2993
 
2994
    /**
2995
     * Check that the user has enough permission to retrieve message or notifications preferences.
2996
     *
2997
     * @param  int $userid the user id requesting the preferences
2998
     * @return stdClass full user object
2999
     * @throws moodle_exception
3000
     * @since  Moodle 3.2
3001
     */
3002
    protected static function validate_preferences_permissions($userid) {
3003
        global $USER;
3004
 
3005
        if (empty($userid)) {
3006
            $user = $USER;
3007
        } else {
3008
            $user = core_user::get_user($userid, '*', MUST_EXIST);
3009
            core_user::require_active_user($user);
3010
        }
3011
 
3012
        $systemcontext = context_system::instance();
3013
        self::validate_context($systemcontext);
3014
 
3015
        // Check access control.
3016
        if ($user->id == $USER->id) {
3017
            // Editing own message profile.
3018
            require_capability('moodle/user:editownmessageprofile', $systemcontext);
3019
        } else {
3020
            // Teachers, parents, etc.
3021
            $personalcontext = context_user::instance($user->id);
3022
            require_capability('moodle/user:editmessageprofile', $personalcontext);
3023
        }
3024
        return $user;
3025
    }
3026
 
3027
    /**
3028
     * Returns a notification or message preference structure.
3029
     *
3030
     * @return external_single_structure the structure
3031
     * @since  Moodle 3.2
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
                                                    'enabled' => new external_value(PARAM_BOOL, 'Is enabled?'),
3069
                                                )
3070
                                            ),
3071
                                            'Processors values for this notification'
3072
                                        ),
3073
                                    )
3074
                                ),
3075
                                'List of notificaitons for the component'
3076
                            ),
3077
                        )
3078
                    ),
3079
                    'Available components'
3080
                ),
3081
            )
3082
        );
3083
    }
3084
 
3085
    /**
3086
     * Returns description of method parameters
3087
     *
3088
     * @return external_function_parameters
3089
     * @since 3.2
3090
     */
3091
    public static function get_user_notification_preferences_parameters() {
3092
        return new external_function_parameters(
3093
            array(
3094
                'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3095
            )
3096
        );
3097
    }
3098
 
3099
    /**
3100
     * Get the notification preferences for a given user.
3101
     *
3102
     * @param int $userid id of the user, 0 for current user
3103
     * @return \core_external\external_description
3104
     * @throws moodle_exception
3105
     * @since 3.2
3106
     */
3107
    public static function get_user_notification_preferences($userid = 0) {
3108
        global $PAGE;
3109
 
3110
        $params = self::validate_parameters(
3111
            self::get_user_notification_preferences_parameters(),
3112
            array(
3113
                'userid' => $userid,
3114
            )
3115
        );
3116
        $user = self::validate_preferences_permissions($params['userid']);
3117
 
3118
        $processors = get_message_processors();
3119
        $providers = message_get_providers_for_user($user->id);
3120
        $preferences = \core_message\api::get_all_message_preferences($processors, $providers, $user);
3121
        $notificationlist = new \core_message\output\preferences\notification_list($processors, $providers, $preferences, $user);
3122
 
3123
        $renderer = $PAGE->get_renderer('core_message');
3124
 
3125
        $result = array(
3126
            'warnings' => array(),
3127
            'preferences' => $notificationlist->export_for_template($renderer)
3128
        );
3129
        return $result;
3130
    }
3131
 
3132
    /**
3133
     * Returns description of method result value
3134
     *
3135
     * @return \core_external\external_description
3136
     * @since 3.2
3137
     */
3138
    public static function get_user_notification_preferences_returns() {
3139
        return new external_function_parameters(
3140
            array(
3141
                'preferences' => self::get_preferences_structure(),
3142
                'warnings' => new external_warnings(),
3143
            )
3144
        );
3145
    }
3146
 
3147
    /**
3148
     * Returns description of method parameters
3149
     *
3150
     * @return external_function_parameters
3151
     * @since 3.2
3152
     */
3153
    public static function get_user_message_preferences_parameters() {
3154
        return new external_function_parameters(
3155
            array(
3156
                'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3157
            )
3158
        );
3159
    }
3160
 
3161
    /**
3162
     * Get the notification preferences for a given user.
3163
     *
3164
     * @param int $userid id of the user, 0 for current user
3165
     * @return \core_external\external_description
3166
     * @throws moodle_exception
3167
     * @since 3.2
3168
     */
3169
    public static function get_user_message_preferences($userid = 0) {
3170
        global $CFG, $PAGE;
3171
 
3172
        $params = self::validate_parameters(
3173
            self::get_user_message_preferences_parameters(),
3174
            array(
3175
                'userid' => $userid,
3176
            )
3177
        );
3178
 
3179
        $user = self::validate_preferences_permissions($params['userid']);
3180
 
3181
        // Filter out enabled, available system_configured and user_configured processors only.
3182
        $readyprocessors = array_filter(get_message_processors(), function($processor) {
3183
            return $processor->enabled &&
3184
                $processor->configured &&
3185
                $processor->object->is_user_configured() &&
3186
                // Filter out processors that don't have and message preferences to configure.
3187
                $processor->object->has_message_preferences();
3188
        });
3189
 
3190
        $providers = array_filter(message_get_providers_for_user($user->id), function($provider) {
3191
            return $provider->component === 'moodle';
3192
        });
3193
        $preferences = \core_message\api::get_all_message_preferences($readyprocessors, $providers, $user);
3194
        $notificationlistoutput = new \core_message\output\preferences\message_notification_list($readyprocessors,
3195
            $providers, $preferences, $user);
3196
 
3197
        $renderer = $PAGE->get_renderer('core_message');
3198
 
3199
        $entertosend = get_user_preferences('message_entertosend', $CFG->messagingdefaultpressenter, $user);
3200
 
3201
        $result = array(
3202
            'warnings' => array(),
3203
            'preferences' => $notificationlistoutput->export_for_template($renderer),
3204
            'blocknoncontacts' => \core_message\api::get_user_privacy_messaging_preference($user->id),
3205
            'entertosend' => $entertosend
3206
        );
3207
        return $result;
3208
    }
3209
 
3210
    /**
3211
     * Returns description of method result value
3212
     *
3213
     * @return \core_external\external_description
3214
     * @since 3.2
3215
     */
3216
    public static function get_user_message_preferences_returns() {
3217
        return new external_function_parameters(
3218
            array(
3219
                'preferences' => self::get_preferences_structure(),
3220
                'blocknoncontacts' => new external_value(PARAM_INT, 'Privacy messaging setting to define who can message you'),
3221
                'entertosend' => new external_value(PARAM_BOOL, 'User preference for using enter to send messages'),
3222
                'warnings' => new external_warnings(),
3223
            )
3224
        );
3225
    }
3226
 
3227
    /**
3228
     * Returns description of method parameters for the favourite_conversations() method.
3229
     *
3230
     * @return external_function_parameters
3231
     */
3232
    public static function set_favourite_conversations_parameters() {
3233
        return new external_function_parameters(
3234
            array(
3235
                'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0),
3236
                'conversations' => new external_multiple_structure(
3237
                    new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0)
3238
                )
3239
            )
3240
        );
3241
    }
3242
 
3243
    /**
3244
     * Favourite a conversation, or list of conversations for a user.
3245
     *
3246
     * @param int $userid the id of the user, or 0 for the current user.
3247
     * @param array $conversationids the list of conversations ids to favourite.
3248
     * @return array
3249
     * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3250
     */
3251
    public static function set_favourite_conversations(int $userid, array $conversationids) {
3252
        global $CFG, $USER;
3253
 
3254
        // All the business logic checks that really shouldn't be in here.
3255
        if (empty($CFG->messaging)) {
3256
            throw new moodle_exception('disabled', 'message');
3257
        }
3258
        $params = [
3259
            'userid' => $userid,
3260
            'conversations' => $conversationids
3261
        ];
3262
        $params = self::validate_parameters(self::set_favourite_conversations_parameters(), $params);
3263
        $systemcontext = context_system::instance();
3264
        self::validate_context($systemcontext);
3265
 
3266
        if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3267
            throw new moodle_exception('You do not have permission to perform this action.');
3268
        }
3269
 
3270
        foreach ($params['conversations'] as $conversationid) {
3271
            \core_message\api::set_favourite_conversation($conversationid, $params['userid']);
3272
        }
3273
 
3274
        return [];
3275
    }
3276
 
3277
    /**
3278
     * Return a description of the returns for the create_user_favourite_conversations() method.
3279
     *
3280
     * @return \core_external\external_description
3281
     */
3282
    public static function set_favourite_conversations_returns() {
3283
        return new external_warnings();
3284
    }
3285
 
3286
    /**
3287
     * Returns description of method parameters for unfavourite_conversations() method.
3288
     *
3289
     * @return external_function_parameters
3290
     */
3291
    public static function unset_favourite_conversations_parameters() {
3292
        return new external_function_parameters(
3293
            array(
3294
                'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0),
3295
                'conversations' => new external_multiple_structure(
3296
                    new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0)
3297
                )
3298
            )
3299
        );
3300
    }
3301
 
3302
    /**
3303
     * Unfavourite a conversation, or list of conversations for a user.
3304
     *
3305
     * @param int $userid the id of the user, or 0 for the current user.
3306
     * @param array $conversationids the list of conversations ids unset as favourites.
3307
     * @return array
3308
     * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3309
     */
3310
    public static function unset_favourite_conversations(int $userid, array $conversationids) {
3311
        global $CFG, $USER;
3312
 
3313
        // All the business logic checks that really shouldn't be in here.
3314
        if (empty($CFG->messaging)) {
3315
            throw new moodle_exception('disabled', 'message');
3316
        }
3317
        $params = [
3318
            'userid' => $userid,
3319
            'conversations' => $conversationids
3320
        ];
3321
        $params = self::validate_parameters(self::unset_favourite_conversations_parameters(), $params);
3322
        $systemcontext = context_system::instance();
3323
        self::validate_context($systemcontext);
3324
 
3325
        if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3326
            throw new moodle_exception('You do not have permission to perform this action.');
3327
        }
3328
 
3329
        foreach ($params['conversations'] as $conversationid) {
3330
            \core_message\api::unset_favourite_conversation($conversationid, $params['userid']);
3331
        }
3332
 
3333
        return [];
3334
    }
3335
 
3336
    /**
3337
     * Unset favourite conversations return description.
3338
     *
3339
     * @return \core_external\external_description
3340
     */
3341
    public static function unset_favourite_conversations_returns() {
3342
        return new external_warnings();
3343
    }
3344
 
3345
    /**
3346
     * Returns description of method parameters for get_member_info() method.
3347
     *
3348
     * @return external_function_parameters
3349
     */
3350
    public static function get_member_info_parameters() {
3351
        return new external_function_parameters(
3352
            array(
3353
                'referenceuserid' => new external_value(PARAM_INT, 'id of the user'),
3354
                'userids' => new external_multiple_structure(
3355
                    new external_value(PARAM_INT, 'id of members to get')
3356
                ),
3357
                'includecontactrequests' => new external_value(PARAM_BOOL, 'include contact requests in response', VALUE_DEFAULT, false),
3358
                'includeprivacyinfo' => new external_value(PARAM_BOOL, 'include privacy info in response', VALUE_DEFAULT, false)
3359
            )
3360
        );
3361
    }
3362
 
3363
    /**
3364
     * Returns conversation member info for the supplied users, relative to the supplied referenceuserid.
3365
     *
3366
     * This is the basic structure used when returning members, and includes information about the relationship between each member
3367
     * and the referenceuser, such as a whether the referenceuser has marked the member as a contact, or has blocked them.
3368
     *
3369
     * @param int $referenceuserid the id of the user which check contact and blocked status.
3370
     * @param array $userids
3371
     * @return array the array of objects containing member info.
3372
     * @throws moodle_exception if messaging is disabled or if the user cannot perform the action.
3373
     */
3374
    public static function get_member_info(
3375
        int $referenceuserid,
3376
        array $userids,
3377
        bool $includecontactrequests = false,
3378
        bool $includeprivacyinfo = false
3379
    ) {
1441 ariadna 3380
        global $CFG, $USER, $DB;
1 efrain 3381
 
3382
        // All the business logic checks that really shouldn't be in here.
3383
        if (empty($CFG->messaging)) {
3384
            throw new moodle_exception('disabled', 'message');
3385
        }
3386
        $params = [
3387
            'referenceuserid' => $referenceuserid,
3388
            'userids' => $userids,
3389
            'includecontactrequests' => $includecontactrequests,
3390
            'includeprivacyinfo' => $includeprivacyinfo
3391
        ];
3392
        $params = self::validate_parameters(self::get_member_info_parameters(), $params);
3393
        $systemcontext = context_system::instance();
3394
        self::validate_context($systemcontext);
3395
 
3396
        if (($USER->id != $referenceuserid) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3397
            throw new moodle_exception('You do not have permission to perform this action.');
3398
        }
3399
 
1441 ariadna 3400
        // Return early if no userids are provided.
3401
        if (empty($params['userids'])) {
3402
            return [];
3403
        }
3404
 
3405
        // Filter the user IDs, removing the IDs of the users that the current user cannot view.
3406
        require_once($CFG->dirroot . '/user/lib.php');
3407
        $userfieldsapi = \core_user\fields::for_userpic()->including('username', 'deleted');
3408
        $userfields = $userfieldsapi->get_sql('', false, '', '', false)->selects;
3409
        $users = $DB->get_records_list('user', 'id', $userids, '', $userfields, 0, 100);
3410
        $filteredids = array_filter($params['userids'], function($userid) use ($users, $params) {
3411
            $targetuser = $users[$userid];
3412
            // Check if the user has the contact already.
3413
            $iscontact = \core_message\api::is_contact($params['referenceuserid'], $userid);
3414
            if ($iscontact) {
3415
                // User is a contact, so we can return the info for this user.
3416
                return true;
3417
            } else {
3418
                // User is not a contact, so we need to check if the user is allowed to see the profile or not.
3419
                return user_can_view_profile($targetuser);
3420
            }
3421
        });
3422
 
3423
        // Return early if no user IDs are left after filtering.
3424
        if (empty($filteredids)) {
3425
            return [];
3426
        }
3427
 
1 efrain 3428
        return \core_message\helper::get_member_info(
3429
            $params['referenceuserid'],
1441 ariadna 3430
            $filteredids,
1 efrain 3431
            $params['includecontactrequests'],
3432
            $params['includeprivacyinfo']
3433
        );
3434
    }
3435
 
3436
    /**
3437
     * Get member info return description.
3438
     *
3439
     * @return \core_external\external_description
3440
     */
3441
    public static function get_member_info_returns() {
3442
        return new external_multiple_structure(
3443
            self::get_conversation_member_structure()
3444
        );
3445
    }
3446
 
3447
    /**
3448
     * Returns description of method parameters for get_conversation_counts() method.
3449
     *
3450
     * @return external_function_parameters
3451
     */
3452
    public static function get_conversation_counts_parameters() {
3453
        return new external_function_parameters(
3454
            [
3455
                'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3456
            ]
3457
        );
3458
    }
3459
 
3460
    /**
3461
     * Returns an array of conversation counts for the various types of conversations, including favourites.
3462
     *
3463
     * Return format:
3464
     * [
3465
     *     'favourites' => 0,
3466
     *     'types' => [
3467
     *          \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
3468
     *          \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => 0
3469
     *      ]
3470
     * ]
3471
     *
3472
     * @param int $userid the id of the user whose counts we are fetching.
3473
     * @return array the array of conversation counts, indexed by type.
3474
     * @throws moodle_exception if the current user cannot perform this action.
3475
     */
3476
    public static function get_conversation_counts(int $userid) {
3477
        global $CFG, $USER;
3478
 
3479
        // All the business logic checks that really shouldn't be in here.
3480
        if (empty($CFG->messaging)) {
3481
            throw new moodle_exception('disabled', 'message');
3482
        }
3483
 
3484
        if (empty($userid)) {
3485
            $userid = $USER->id;
3486
        }
3487
 
3488
        $params = ['userid' => $userid];
3489
        $params = self::validate_parameters(self::get_conversation_counts_parameters(), $params);
3490
 
3491
        $systemcontext = context_system::instance();
3492
        self::validate_context($systemcontext);
3493
 
3494
        if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3495
            throw new moodle_exception('You do not have permission to perform this action.');
3496
        }
3497
 
3498
        return \core_message\api::get_conversation_counts($params['userid']);
3499
    }
3500
 
3501
    /**
3502
     * Get conversation counts return description.
3503
     *
3504
     * @return \core_external\external_description
3505
     */
3506
    public static function get_conversation_counts_returns() {
3507
        return new external_single_structure(
3508
            [
3509
                'favourites' => new external_value(PARAM_INT, 'Total number of favourite conversations'),
3510
                'types' => new external_single_structure(
3511
                    [
3512
                        \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => new external_value(PARAM_INT,
3513
                            'Total number of individual conversations'),
3514
                        \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => new external_value(PARAM_INT,
3515
                            'Total number of group conversations'),
3516
                        \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF => new external_value(PARAM_INT,
3517
                            'Total number of self conversations'),
3518
                    ]
3519
                ),
3520
            ]
3521
        );
3522
    }
3523
 
3524
    /**
3525
     * Returns description of method parameters for get_unread_conversation_counts() method.
3526
     *
3527
     * @return external_function_parameters
3528
     */
3529
    public static function get_unread_conversation_counts_parameters() {
3530
        return new external_function_parameters(
3531
            [
3532
                'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0)
3533
            ]
3534
        );
3535
    }
3536
 
3537
    /**
3538
     * Returns an array of unread conversation counts for the various types of conversations, including favourites.
3539
     *
3540
     * Return format:
3541
     * [
3542
     *     'favourites' => 0,
3543
     *     'types' => [
3544
     *          \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
3545
     *          \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => 0
3546
     *      ]
3547
     * ]
3548
     *
3549
     * @param int $userid the id of the user whose counts we are fetching.
3550
     * @return array the array of unread conversation counts, indexed by type.
3551
     * @throws moodle_exception if the current user cannot perform this action.
3552
     */
3553
    public static function get_unread_conversation_counts(int $userid) {
3554
        global $CFG, $USER;
3555
 
3556
        // All the business logic checks that really shouldn't be in here.
3557
        if (empty($CFG->messaging)) {
3558
            throw new moodle_exception('disabled', 'message');
3559
        }
3560
 
3561
        if (empty($userid)) {
3562
            $userid = $USER->id;
3563
        }
3564
 
3565
        $params = ['userid' => $userid];
3566
        $params = self::validate_parameters(self::get_unread_conversation_counts_parameters(), $params);
3567
 
3568
        $systemcontext = context_system::instance();
3569
        self::validate_context($systemcontext);
3570
 
3571
        if (($USER->id != $params['userid']) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
3572
            throw new moodle_exception('You do not have permission to perform this action.');
3573
        }
3574
 
3575
        return \core_message\api::get_unread_conversation_counts($params['userid']);
3576
    }
3577
 
3578
    /**
3579
     * Get unread conversation counts return description.
3580
     *
3581
     * @return \core_external\external_description
3582
     */
3583
    public static function get_unread_conversation_counts_returns() {
3584
        return new external_single_structure(
3585
            [
3586
                'favourites' => new external_value(PARAM_INT, 'Total number of unread favourite conversations'),
3587
                'types' => new external_single_structure(
3588
                    [
3589
                        \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => new external_value(PARAM_INT,
3590
                            'Total number of unread individual conversations'),
3591
                        \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP => new external_value(PARAM_INT,
3592
                            'Total number of unread group conversations'),
3593
                        \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF => new external_value(PARAM_INT,
3594
                            'Total number of unread self conversations'),
3595
                    ]
3596
                ),
3597
            ]
3598
        );
3599
    }
3600
 
3601
    /**
3602
     * Returns description of method parameters
3603
     *
3604
     * @return external_function_parameters
3605
     * @since 3.7
3606
     */
3607
    public static function delete_message_for_all_users_parameters() {
3608
        return new external_function_parameters(
3609
            array(
3610
                'messageid' => new external_value(PARAM_INT, 'The message id'),
3611
                'userid' => new external_value(PARAM_INT, 'The user id of who we want to delete the message for all users')
3612
            )
3613
        );
3614
    }
3615
    /**
3616
     * Deletes a message for all users
3617
     *
3618
     * @param  int $messageid the message id
3619
     * @param  int $userid the user id of who we want to delete the message for all users, is no longer used.
3620
     * @return \core_external\external_description
3621
     * @throws moodle_exception
3622
     * @since 3.7
3623
     */
3624
    public static function delete_message_for_all_users(int $messageid, int $userid) {
3625
        global $CFG, $USER;
3626
 
3627
        // Check if private messaging between users is allowed.
3628
        if (empty($CFG->messaging)) {
3629
            throw new moodle_exception('disabled', 'message');
3630
        }
3631
 
3632
        // Validate params.
3633
        $params = array(
3634
            'messageid' => $messageid,
3635
            'userid' => $userid
3636
        );
3637
        $params = self::validate_parameters(self::delete_message_for_all_users_parameters(), $params);
3638
 
3639
        // Validate context.
3640
        $context = context_system::instance();
3641
        self::validate_context($context);
3642
 
3643
        core_user::require_active_user($USER);
3644
 
3645
        // Checks if a user can delete a message for all users.
3646
        if (core_message\api::can_delete_message_for_all_users($USER->id, $params['messageid'])) {
3647
            \core_message\api::delete_message_for_all_users($params['messageid']);
3648
        } else {
3649
            throw new moodle_exception('You do not have permission to delete this message for everyone.');
3650
        }
3651
 
3652
        return [];
3653
    }
3654
    /**
3655
     * Returns description of method result value
3656
     *
3657
     * @return \core_external\external_description
3658
     * @since 3.7
3659
     */
3660
    public static function delete_message_for_all_users_returns() {
3661
        return new external_warnings();
3662
    }
3663
}