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