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