abcacd8f89dfce1051dc35cff14044e283b1a670
[moodle.git] / message / tests / api_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Test message API.
19  *
20  * @package core_message
21  * @category test
22  * @copyright 2016 Mark Nelson <markn@moodle.com>
23  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
30 require_once($CFG->dirroot . '/message/tests/messagelib_test.php');
32 use \core_message\tests\helper as testhelper;
34 /**
35  * Test message API.
36  *
37  * @package core_message
38  * @category test
39  * @copyright 2016 Mark Nelson <markn@moodle.com>
40  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
41  */
42 class core_message_api_testcase extends core_message_messagelib_testcase {
44     public function test_mark_all_read_for_user_touser() {
45         $sender = $this->getDataGenerator()->create_user(array('firstname' => 'Test1', 'lastname' => 'User1'));
46         $recipient = $this->getDataGenerator()->create_user(array('firstname' => 'Test2', 'lastname' => 'User2'));
48         $this->send_fake_message($sender, $recipient, 'Notification', 1);
49         $this->send_fake_message($sender, $recipient, 'Notification', 1);
50         $this->send_fake_message($sender, $recipient, 'Notification', 1);
51         $this->send_fake_message($sender, $recipient);
52         $this->send_fake_message($sender, $recipient);
53         $this->send_fake_message($sender, $recipient);
55         \core_message\api::mark_all_notifications_as_read($recipient->id);
56         \core_message\api::mark_all_messages_as_read($recipient->id);
58         $this->assertEquals(message_count_unread_messages($recipient), 0);
59         $this->assertDebuggingCalled();
60     }
62     public function test_mark_all_read_for_user_touser_with_fromuser() {
63         $sender1 = $this->getDataGenerator()->create_user(array('firstname' => 'Test1', 'lastname' => 'User1'));
64         $sender2 = $this->getDataGenerator()->create_user(array('firstname' => 'Test3', 'lastname' => 'User3'));
65         $recipient = $this->getDataGenerator()->create_user(array('firstname' => 'Test2', 'lastname' => 'User2'));
67         $this->send_fake_message($sender1, $recipient, 'Notification', 1);
68         $this->send_fake_message($sender1, $recipient, 'Notification', 1);
69         $this->send_fake_message($sender1, $recipient, 'Notification', 1);
70         $this->send_fake_message($sender1, $recipient);
71         $this->send_fake_message($sender1, $recipient);
72         $this->send_fake_message($sender1, $recipient);
73         $this->send_fake_message($sender2, $recipient, 'Notification', 1);
74         $this->send_fake_message($sender2, $recipient, 'Notification', 1);
75         $this->send_fake_message($sender2, $recipient, 'Notification', 1);
76         $this->send_fake_message($sender2, $recipient);
77         $this->send_fake_message($sender2, $recipient);
78         $this->send_fake_message($sender2, $recipient);
80         \core_message\api::mark_all_notifications_as_read($recipient->id, $sender1->id);
81         $conversationid = \core_message\api::get_conversation_between_users([$recipient->id, $sender1->id]);
82         \core_message\api::mark_all_messages_as_read($recipient->id, $conversationid);
84         $this->assertEquals(message_count_unread_messages($recipient), 3);
85         $this->assertDebuggingCalled();
86     }
88     public function test_mark_all_read_for_user_touser_with_type() {
89         $sender = $this->getDataGenerator()->create_user(array('firstname' => 'Test1', 'lastname' => 'User1'));
90         $recipient = $this->getDataGenerator()->create_user(array('firstname' => 'Test2', 'lastname' => 'User2'));
92         $this->send_fake_message($sender, $recipient, 'Notification', 1);
93         $this->send_fake_message($sender, $recipient, 'Notification', 1);
94         $this->send_fake_message($sender, $recipient, 'Notification', 1);
95         $this->send_fake_message($sender, $recipient);
96         $this->send_fake_message($sender, $recipient);
97         $this->send_fake_message($sender, $recipient);
99         \core_message\api::mark_all_notifications_as_read($recipient->id);
100         $this->assertEquals(message_count_unread_messages($recipient), 3);
101         $this->assertDebuggingCalled();
103         \core_message\api::mark_all_messages_as_read($recipient->id);
104         $this->assertEquals(message_count_unread_messages($recipient), 0);
105         $this->assertDebuggingCalled();
106     }
108     /**
109      * Test count_blocked_users.
110      */
111     public function test_count_blocked_users() {
112         global $USER;
114         // Set this user as the admin.
115         $this->setAdminUser();
117         // Create user to add to the admin's block list.
118         $user1 = $this->getDataGenerator()->create_user();
119         $user2 = $this->getDataGenerator()->create_user();
121         $this->assertEquals(0, \core_message\api::count_blocked_users());
123         // Add 1 blocked user to admin's blocked user list.
124         \core_message\api::block_user($USER->id, $user1->id);
126         $this->assertEquals(0, \core_message\api::count_blocked_users($user1));
127         $this->assertEquals(1, \core_message\api::count_blocked_users());
128     }
130     /**
131      * Tests searching for users when site-wide messaging is disabled.
132      *
133      * This test verifies that any contacts are returned, as well as any non-contacts whose profile we can view.
134      * If checks this by placing some users in the same course, where default caps would permit a user to view another user's
135      * profile.
136      */
137     public function test_message_search_users_messagingallusers_disabled() {
138         global $DB;
139         $this->resetAfterTest();
141         // Create some users.
142         $users = [];
143         foreach (range(1, 8) as $i) {
144             $user = new stdClass();
145             $user->firstname = ($i == 4) ? 'User' : 'User search'; // Ensure the fourth user won't match the search term.
146             $user->lastname = $i;
147             $user = $this->getDataGenerator()->create_user($user);
148             $users[$i] = $user;
149         }
151         // Enrol a few users in the same course, but leave them as non-contacts.
152         $course1 = $this->getDataGenerator()->create_course();
153         $course2 = $this->getDataGenerator()->create_course();
155         $this->setAdminUser();
156         $this->getDataGenerator()->enrol_user($users[1]->id, $course1->id);
157         $this->getDataGenerator()->enrol_user($users[6]->id, $course1->id);
158         $this->getDataGenerator()->enrol_user($users[7]->id, $course1->id);
160         // Add some other users as contacts.
161         \core_message\api::add_contact($users[1]->id, $users[2]->id);
162         \core_message\api::add_contact($users[3]->id, $users[1]->id);
163         \core_message\api::add_contact($users[1]->id, $users[4]->id);
165         // Enrol a user as a teacher in the course, and make the teacher role a course contact role.
166         $this->getDataGenerator()->enrol_user($users[8]->id, $course2->id, 'editingteacher');
167         $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
168         set_config('coursecontact', $teacherrole->id);
170         // Create individual conversations between some users, one contact and one non-contact.
171         $ic1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
172             [$users[1]->id, $users[2]->id]);
173         $ic2 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
174             [$users[6]->id, $users[1]->id]);
176         // Create a group conversation between 4 users, including a contact and a non-contact.
177         $gc1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
178             [$users[1]->id, $users[2]->id, $users[4]->id, $users[7]->id], 'Project chat');
180         // Set as the user performing the search.
181         $this->setUser($users[1]);
183         // Perform a search with $CFG->messagingallusers disabled.
184         set_config('messagingallusers', 0);
185         $result = \core_message\api::message_search_users($users[1]->id, 'search');
187         // Confirm that we returns contacts and non-contacts.
188         $this->assertArrayHasKey(0, $result);
189         $this->assertArrayHasKey(1, $result);
190         $contacts = $result[0];
191         $noncontacts = $result[1];
193         // Check that we retrieved the correct contacts.
194         $this->assertCount(2, $contacts);
195         $this->assertEquals($users[2]->id, $contacts[0]->id);
196         $this->assertEquals($users[3]->id, $contacts[1]->id);
198         // Verify the correct conversations were returned for the contacts.
199         $this->assertCount(2, $contacts[0]->conversations);
200         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $contacts[0]->conversations[$gc1->id]->type);
201         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $contacts[0]->conversations[$ic1->id]->type);
203         $this->assertCount(0, $contacts[1]->conversations);
205         // Check that we retrieved the correct non-contacts.
206         // When site wide messaging is disabled, we expect to see only those users who we share a course with and whose profiles
207         // are visible in that course. This excludes users like course contacts.
208         $this->assertCount(3, $noncontacts);
209         // Self-conversation first.
210         $this->assertEquals($users[1]->id, $noncontacts[0]->id);
211         $this->assertEquals($users[6]->id, $noncontacts[1]->id);
212         $this->assertEquals($users[7]->id, $noncontacts[2]->id);
214         // Verify the correct conversations were returned for the non-contacts.
215         $this->assertCount(1, $noncontacts[1]->conversations);
216         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
217             $noncontacts[1]->conversations[$ic2->id]->type);
219         $this->assertCount(1, $noncontacts[2]->conversations);
220         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $noncontacts[2]->conversations[$gc1->id]->type);
221     }
223     /**
224      * Tests searching for users when site-wide messaging is enabled.
225      *
226      * This test verifies that any contacts are returned, as well as any non-contacts,
227      * provided the searching user can view their profile.
228      */
229     public function test_message_search_users_messagingallusers_enabled() {
230         global $DB;
231         $this->resetAfterTest();
233         // Create some users.
234         $users = [];
235         foreach (range(1, 9) as $i) {
236             $user = new stdClass();
237             $user->firstname = ($i == 4) ? 'User' : 'User search'; // Ensure the fourth user won't match the search term.
238             $user->lastname = $i;
239             $user = $this->getDataGenerator()->create_user($user);
240             $users[$i] = $user;
241         }
243         $course1 = $this->getDataGenerator()->create_course();
244         $coursecontext = \context_course::instance($course1->id);
246         // Enrol a few users in the same course, but leave them as non-contacts.
247         $this->setAdminUser();
248         $this->getDataGenerator()->enrol_user($users[1]->id, $course1->id, 'student');
249         $this->getDataGenerator()->enrol_user($users[6]->id, $course1->id, 'student');
250         $this->getDataGenerator()->enrol_user($users[7]->id, $course1->id, 'student');
252         // Add some other users as contacts.
253         \core_message\api::add_contact($users[1]->id, $users[2]->id);
254         \core_message\api::add_contact($users[3]->id, $users[1]->id);
255         \core_message\api::add_contact($users[1]->id, $users[4]->id);
257         // Enrol a user as a teacher in the course, and make the teacher role a course contact role.
258         $this->getDataGenerator()->enrol_user($users[9]->id, $course1->id, 'editingteacher');
259         $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
260         set_config('coursecontact', $teacherrole->id);
262         // Get self-conversation.
263         $selfconversation = \core_message\api::get_self_conversation($users[1]->id);
265         // Create individual conversations between some users, one contact and one non-contact.
266         $ic1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
267             [$users[1]->id, $users[2]->id]);
268         $ic2 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
269             [$users[6]->id, $users[1]->id]);
271         // Create a group conversation between 5 users, including a contact and a non-contact, and a user NOT in a shared course.
272         $gc1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
273             [$users[1]->id, $users[2]->id, $users[4]->id, $users[7]->id, $users[8]->id], 'Project chat');
275         // Set as the user performing the search.
276         $this->setUser($users[1]);
278         // Perform a search with $CFG->messagingallusers enabled.
279         set_config('messagingallusers', 1);
280         $result = \core_message\api::message_search_users($users[1]->id, 'search');
282         // Confirm that we returns contacts and non-contacts.
283         $this->assertArrayHasKey(0, $result);
284         $this->assertArrayHasKey(1, $result);
285         $contacts = $result[0];
286         $noncontacts = $result[1];
288         // Check that we retrieved the correct contacts.
289         $this->assertCount(2, $contacts);
290         $this->assertEquals($users[2]->id, $contacts[0]->id);
291         $this->assertEquals($users[3]->id, $contacts[1]->id);
293         // Verify the correct conversations were returned for the contacts.
294         $this->assertCount(2, $contacts[0]->conversations);
295         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $contacts[0]->conversations[$gc1->id]->type);
296         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $contacts[0]->conversations[$ic1->id]->type);
298         $this->assertCount(0, $contacts[1]->conversations);
300         // Check that we retrieved the correct non-contacts.
301         // If site wide messaging is enabled, we expect to only be able to search for users whose profiles we can view.
302         // In this case, as a student, that's the course contact for course2 and those noncontacts sharing a course with user1.
303         // Consider first conversations is self-conversation.
304         $this->assertCount(4, $noncontacts);
305         $this->assertEquals($users[1]->id, $noncontacts[0]->id);
306         $this->assertEquals($users[6]->id, $noncontacts[1]->id);
307         $this->assertEquals($users[7]->id, $noncontacts[2]->id);
308         $this->assertEquals($users[9]->id, $noncontacts[3]->id);
310         $this->assertCount(1, $noncontacts[1]->conversations);
311         $this->assertCount(1, $noncontacts[2]->conversations);
312         $this->assertCount(0, $noncontacts[3]->conversations);
314         // Verify the correct conversations were returned for the non-contacts.
315         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_SELF,
316             $noncontacts[0]->conversations[$selfconversation->id]->type);
318         $this->assertCount(1, $noncontacts[1]->conversations);
319         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
320             $noncontacts[1]->conversations[$ic2->id]->type);
322         $this->assertCount(1, $noncontacts[2]->conversations);
323         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $noncontacts[2]->conversations[$gc1->id]->type);
325         $this->assertCount(0, $noncontacts[3]->conversations);
326     }
328     /**
329      * Verify searching for users find themselves when they have self-conversations.
330      */
331     public function test_message_search_users_self_conversations() {
332         $this->resetAfterTest();
334         // Create some users.
335         $user1 = new stdClass();
336         $user1->firstname = 'User';
337         $user1->lastname = 'One';
338         $user1 = $this->getDataGenerator()->create_user($user1);
339         $user2 = new stdClass();
340         $user2->firstname = 'User';
341         $user2->lastname = 'Two';
342         $user2 = $this->getDataGenerator()->create_user($user2);
344         // Get self-conversation for user1.
345         $sc1 = \core_message\api::get_self_conversation($user1->id);
346         testhelper::send_fake_message_to_conversation($user1, $sc1->id, 'Hi myself!');
348         // Perform a search as user1.
349         $this->setUser($user1);
350         $result = \core_message\api::message_search_users($user1->id, 'One');
352         // Check user1 is found as non-contacts.
353         $this->assertCount(0, $result[0]);
354         $this->assertCount(1, $result[1]);
355     }
357     /**
358      * Verify searching for users works even if no matching users from either contacts, or non-contacts can be found.
359      */
360     public function test_message_search_users_with_empty_result() {
361         $this->resetAfterTest();
363         // Create some users, but make sure neither will match the search term.
364         $user1 = new stdClass();
365         $user1->firstname = 'User';
366         $user1->lastname = 'One';
367         $user1 = $this->getDataGenerator()->create_user($user1);
368         $user2 = new stdClass();
369         $user2->firstname = 'User';
370         $user2->lastname = 'Two';
371         $user2 = $this->getDataGenerator()->create_user($user2);
373         // Perform a search as user1.
374         $this->setUser($user1);
375         $result = \core_message\api::message_search_users($user1->id, 'search');
377         // Check results are empty.
378         $this->assertCount(0, $result[0]);
379         $this->assertCount(0, $result[1]);
380     }
382     /**
383      * Test verifying that limits and offsets work for both the contacts and non-contacts return data.
384      */
385     public function test_message_search_users_limit_offset() {
386         $this->resetAfterTest();
388         // Create 20 users.
389         $users = [];
390         foreach (range(1, 20) as $i) {
391             $user = new stdClass();
392             $user->firstname = "User search";
393             $user->lastname = $i;
394             $user = $this->getDataGenerator()->create_user($user);
395             $users[$i] = $user;
396         }
398         // Enrol the first 9 users in the same course, but leave them as non-contacts.
399         $this->setAdminUser();
400         $course1 = $this->getDataGenerator()->create_course();
401         foreach (range(1, 8) as $i) {
402             $this->getDataGenerator()->enrol_user($users[$i]->id, $course1->id);
403         }
405         // Add 5 users, starting at the 11th user, as contacts for user1.
406         foreach (range(11, 15) as $i) {
407             \core_message\api::add_contact($users[1]->id, $users[$i]->id);
408         }
410         // Set as the user performing the search.
411         $this->setUser($users[1]);
413         // Search using a limit of 3.
414         // This tests the case where we have more results than the limit for both contacts and non-contacts.
415         $result = \core_message\api::message_search_users($users[1]->id, 'search', 0, 3);
416         $contacts = $result[0];
417         $noncontacts = $result[1];
419         // Check that we retrieved the correct contacts.
420         $this->assertCount(3, $contacts);
421         $this->assertEquals($users[11]->id, $contacts[0]->id);
422         $this->assertEquals($users[12]->id, $contacts[1]->id);
423         $this->assertEquals($users[13]->id, $contacts[2]->id);
425         // Check that we retrieved the correct non-contacts.
426         // Consider first conversations is self-conversation.
427         $this->assertCount(3, $noncontacts);
428         $this->assertEquals($users[1]->id, $noncontacts[0]->id);
429         $this->assertEquals($users[2]->id, $noncontacts[1]->id);
430         $this->assertEquals($users[3]->id, $noncontacts[2]->id);
432         // Now, offset to get the next batch of results.
433         // We expect to see 2 contacts, and 3 non-contacts.
434         $result = \core_message\api::message_search_users($users[1]->id, 'search', 3, 3);
435         $contacts = $result[0];
436         $noncontacts = $result[1];
437         $this->assertCount(2, $contacts);
438         $this->assertEquals($users[14]->id, $contacts[0]->id);
439         $this->assertEquals($users[15]->id, $contacts[1]->id);
441         $this->assertCount(3, $noncontacts);
442         $this->assertEquals($users[4]->id, $noncontacts[0]->id);
443         $this->assertEquals($users[5]->id, $noncontacts[1]->id);
444         $this->assertEquals($users[6]->id, $noncontacts[2]->id);
446         // Now, offset to get the next batch of results.
447         // We expect to see 0 contacts, and 2 non-contacts.
448         $result = \core_message\api::message_search_users($users[1]->id, 'search', 6, 3);
449         $contacts = $result[0];
450         $noncontacts = $result[1];
451         $this->assertCount(0, $contacts);
453         $this->assertCount(2, $noncontacts);
454         $this->assertEquals($users[7]->id, $noncontacts[0]->id);
455         $this->assertEquals($users[8]->id, $noncontacts[1]->id);
456     }
458     /**
459      * Tests searching users as a user having the 'moodle/user:viewdetails' capability.
460      */
461     public function test_message_search_users_with_cap() {
462         $this->resetAfterTest();
463         global $DB;
465         // Create some users.
466         $users = [];
467         foreach (range(1, 8) as $i) {
468             $user = new stdClass();
469             $user->firstname = ($i == 4) ? 'User' : 'User search'; // Ensure the fourth user won't match the search term.
470             $user->lastname = $i;
471             $user = $this->getDataGenerator()->create_user($user);
472             $users[$i] = $user;
473         }
475         // Enrol a few users in the same course, but leave them as non-contacts.
476         $course1 = $this->getDataGenerator()->create_course();
477         $this->setAdminUser();
478         $this->getDataGenerator()->enrol_user($users[1]->id, $course1->id);
479         $this->getDataGenerator()->enrol_user($users[6]->id, $course1->id);
480         $this->getDataGenerator()->enrol_user($users[7]->id, $course1->id);
482         // Add some other users as contacts.
483         \core_message\api::add_contact($users[1]->id, $users[2]->id);
484         \core_message\api::add_contact($users[3]->id, $users[1]->id);
485         \core_message\api::add_contact($users[1]->id, $users[4]->id);
487         // Set as the user performing the search.
488         $this->setUser($users[1]);
490         // Grant the authenticated user role the capability 'user:viewdetails' at site context.
491         $authenticatedrole = $DB->get_record('role', ['shortname' => 'user'], '*', MUST_EXIST);
492         assign_capability('moodle/user:viewdetails', CAP_ALLOW, $authenticatedrole->id, context_system::instance());
494         // Perform a search with $CFG->messagingallusers disabled.
495         set_config('messagingallusers', 0);
496         $result = \core_message\api::message_search_users($users[1]->id, 'search');
497         $contacts = $result[0];
498         $noncontacts = $result[1];
500         // Check that we retrieved the correct contacts.
501         $this->assertCount(2, $contacts);
502         $this->assertEquals($users[2]->id, $contacts[0]->id);
503         $this->assertEquals($users[3]->id, $contacts[1]->id);
505         // Check that we retrieved the correct non-contacts.
506         // Site-wide messaging is disabled, so we expect to be able to search for any users whose profiles we can view.
507         // Consider first conversations is self-conversation.
508         $this->assertCount(3, $noncontacts);
509         $this->assertEquals($users[1]->id, $noncontacts[0]->id);
510         $this->assertEquals($users[6]->id, $noncontacts[1]->id);
511         $this->assertEquals($users[7]->id, $noncontacts[2]->id);
512     }
514     /**
515      * Tests searching users with messaging disabled.
516      */
517     public function test_message_search_users_messaging_disabled() {
518         $this->resetAfterTest();
520         // Create a user.
521         $user = $this->getDataGenerator()->create_user();
523         // Disable messaging.
524         set_config('messaging', 0);
526         // Ensure an exception is thrown.
527         $this->expectException('moodle_exception');
528         \core_message\api::message_search_users($user->id, 'User');
529     }
531     /**
532      * Tests getting conversations between 2 users.
533      */
534     public function test_get_conversations_between_users() {
535         // Create some users.
536         $user1 = new stdClass();
537         $user1->firstname = 'User';
538         $user1->lastname = 'One';
539         $user1 = self::getDataGenerator()->create_user($user1);
541         $user2 = new stdClass();
542         $user2->firstname = 'User';
543         $user2->lastname = 'Two';
544         $user2 = self::getDataGenerator()->create_user($user2);
546         $user3 = new stdClass();
547         $user3->firstname = 'User search';
548         $user3->lastname = 'Three';
549         $user3 = self::getDataGenerator()->create_user($user3);
551         $user4 = new stdClass();
552         $user4->firstname = 'User';
553         $user4->lastname = 'Four';
554         $user4 = self::getDataGenerator()->create_user($user4);
556         $user5 = new stdClass();
557         $user5->firstname = 'User';
558         $user5->lastname = 'Five';
559         $user5 = self::getDataGenerator()->create_user($user5);
561         $user6 = new stdClass();
562         $user6->firstname = 'User search';
563         $user6->lastname = 'Six';
564         $user6 = self::getDataGenerator()->create_user($user6);
566         // Add some users as contacts.
567         \core_message\api::add_contact($user1->id, $user2->id);
568         \core_message\api::add_contact($user6->id, $user1->id);
570         // Create private conversations with some users.
571         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
572             array($user1->id, $user2->id));
573         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
574             array($user3->id, $user1->id));
576         // Create a group conversation with users.
577         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
578             array($user1->id, $user2->id, $user3->id, $user4->id),
579             'Project chat');
581         // Check that we retrieved the correct conversations.
582         $this->assertCount(2, \core_message\api::get_conversations_between_users($user1->id, $user2->id));
583         $this->assertCount(2, \core_message\api::get_conversations_between_users($user2->id, $user1->id));
584         $this->assertCount(2, \core_message\api::get_conversations_between_users($user1->id, $user3->id));
585         $this->assertCount(2, \core_message\api::get_conversations_between_users($user3->id, $user1->id));
586         $this->assertCount(1, \core_message\api::get_conversations_between_users($user1->id, $user4->id));
587         $this->assertCount(1, \core_message\api::get_conversations_between_users($user4->id, $user1->id));
588         $this->assertCount(0, \core_message\api::get_conversations_between_users($user1->id, $user5->id));
589         $this->assertCount(0, \core_message\api::get_conversations_between_users($user5->id, $user1->id));
590         $this->assertCount(0, \core_message\api::get_conversations_between_users($user1->id, $user6->id));
591         $this->assertCount(0, \core_message\api::get_conversations_between_users($user6->id, $user1->id));
592     }
594     /**
595      * Tests getting self-conversations.
596      */
597     public function test_get_self_conversation() {
598         // Create some users.
599         $user1 = new stdClass();
600         $user1->firstname = 'User';
601         $user1->lastname = 'One';
602         $user1 = self::getDataGenerator()->create_user($user1);
604         $user2 = new stdClass();
605         $user2->firstname = 'User';
606         $user2->lastname = 'Two';
607         $user2 = self::getDataGenerator()->create_user($user2);
609         $user3 = new stdClass();
610         $user3->firstname = 'User search';
611         $user3->lastname = 'Three';
612         $user3 = self::getDataGenerator()->create_user($user3);
614         // Add some users as contacts.
615         \core_message\api::add_contact($user1->id, $user2->id);
616         \core_message\api::add_contact($user3->id, $user1->id);
618         // Create private conversations with some users.
619         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
620             array($user1->id, $user2->id));
621         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
622             array($user3->id, $user1->id));
624         // Create a group conversation with users.
625         $gc = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
626             array($user1->id, $user2->id, $user3->id),
627             'Project chat');
629         // Get self-conversations.
630         $rsc1 = \core_message\api::get_self_conversation($user1->id);
631         $rsc2 = \core_message\api::get_self_conversation($user2->id);
632         $rsc3 = \core_message\api::get_self_conversation($user3->id);
634         // Send message to self-conversation.
635         testhelper::send_fake_message_to_conversation($user1, $rsc1->id, 'Message to myself!');
637         // Check that we retrieved the correct conversations.
638         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_SELF, $rsc1->type);
639         $members = \core_message\api::get_conversation_members($user1->id, $rsc1->id);
640         $this->assertCount(1, $members);
641         $member = reset($members);
642         $this->assertEquals($user1->id, $member->id);
644         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_SELF, $rsc2->type);
645         $members = \core_message\api::get_conversation_members($user2->id, $rsc2->id);
646         $this->assertCount(1, $members);
647         $member = reset($members);
648         $this->assertEquals($user2->id, $member->id);
650         \core_message\api::delete_all_conversation_data($rsc3->id);
651         $selfconversation = \core_message\api::get_self_conversation($user3->id);
652         $members = \core_message\api::get_conversation_members($user1->id, $selfconversation->id);
653         $this->assertCount(1, $members);
654     }
656     /**
657      * Tests searching messages.
658      */
659     public function test_search_messages() {
660         $this->resetAfterTest();
662         // Create some users.
663         $user1 = self::getDataGenerator()->create_user();
664         $user2 = self::getDataGenerator()->create_user();
665         $user3 = self::getDataGenerator()->create_user();
667         // The person doing the search.
668         $this->setUser($user1);
670         // Get self-conversation.
671         $sc = \core_message\api::get_self_conversation($user1->id);
673         // Create group conversation.
674         $gc = \core_message\api::create_conversation(
675             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
676             [$user1->id, $user2->id, $user3->id]
677         );
679         // Send some messages back and forth.
680         $time = 1;
681         testhelper::send_fake_message_to_conversation($user1, $sc->id, 'Test message to self!', $time);
682         testhelper::send_fake_message_to_conversation($user1, $gc->id, 'My hero!', $time + 1);
683         $this->send_fake_message($user3, $user1, 'Don\'t block me.', 0, $time + 2);
684         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 3);
685         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 4);
686         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 5);
687         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 6);
689         $convid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
690         $conv2id = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]);
692         // Block user 3.
693         \core_message\api::block_user($user1->id, $user3->id);
695         // Perform a search.
696         $messages = \core_message\api::search_messages($user1->id, 'o');
698         // Confirm the data is correct.
699         $this->assertEquals(5, count($messages));
700         $message1 = $messages[0];
701         $message2 = $messages[1];
702         $message3 = $messages[2];
703         $message4 = $messages[3];
704         $message5 = $messages[4];
706         $this->assertEquals($user2->id, $message1->userid);
707         $this->assertEquals($user2->id, $message1->useridfrom);
708         $this->assertEquals(fullname($user2), $message1->fullname);
709         $this->assertTrue($message1->ismessaging);
710         $this->assertEquals('Word.', $message1->lastmessage);
711         $this->assertNotEmpty($message1->messageid);
712         $this->assertNull($message1->isonline);
713         $this->assertFalse($message1->isread);
714         $this->assertFalse($message1->isblocked);
715         $this->assertNull($message1->unreadcount);
716         $this->assertEquals($convid, $message1->conversationid);
718         $this->assertEquals($user2->id, $message2->userid);
719         $this->assertEquals($user1->id, $message2->useridfrom);
720         $this->assertEquals(fullname($user2), $message2->fullname);
721         $this->assertTrue($message2->ismessaging);
722         $this->assertEquals('Yo!', $message2->lastmessage);
723         $this->assertNotEmpty($message2->messageid);
724         $this->assertNull($message2->isonline);
725         $this->assertTrue($message2->isread);
726         $this->assertFalse($message2->isblocked);
727         $this->assertNull($message2->unreadcount);
728         $this->assertEquals($convid, $message2->conversationid);
730         $this->assertEquals($user3->id, $message3->userid);
731         $this->assertEquals($user3->id, $message3->useridfrom);
732         $this->assertEquals(fullname($user3), $message3->fullname);
733         $this->assertTrue($message3->ismessaging);
734         $this->assertEquals('Don\'t block me.', $message3->lastmessage);
735         $this->assertNotEmpty($message3->messageid);
736         $this->assertNull($message3->isonline);
737         $this->assertFalse($message3->isread);
738         $this->assertTrue($message3->isblocked);
739         $this->assertNull($message3->unreadcount);
740         $this->assertEquals($conv2id, $message3->conversationid);
742         // This is a group conversation. For now, search_messages returns only one of the other users on the conversation. It can't
743         // be guaranteed who will be returned in the first place, so we need to use the in_array to check all the possibilities.
744         $this->assertTrue(in_array($message4->userid, [$user2->id, $user3->id]));
745         $this->assertEquals($user1->id, $message4->useridfrom);
746         $this->assertTrue($message4->ismessaging);
747         $this->assertEquals('My hero!', $message4->lastmessage);
748         $this->assertNotEmpty($message4->messageid);
749         $this->assertNull($message4->isonline);
750         $this->assertTrue($message4->isread);
751         $this->assertNull($message4->unreadcount);
752         $this->assertEquals($gc->id, $message4->conversationid);
754         $this->assertEquals($user1->id, $message5->userid);
755         $this->assertEquals($user1->id, $message5->useridfrom);
756         $this->assertEquals(fullname($user1), $message5->fullname);
757         $this->assertTrue($message5->ismessaging);
758         $this->assertEquals('Test message to self!', $message5->lastmessage);
759         $this->assertNotEmpty($message5->messageid);
760         $this->assertFalse($message5->isonline);
761         $this->assertTrue($message5->isread);
762         $this->assertFalse($message5->isblocked);
763         $this->assertNull($message5->unreadcount);
764         $this->assertEquals($sc->id, $message5->conversationid);
765     }
767     /**
768      * Test verifying that favourited conversations can be retrieved.
769      */
770     public function test_get_favourite_conversations() {
771         // Create some users.
772         $user1 = self::getDataGenerator()->create_user();
773         $user2 = self::getDataGenerator()->create_user();
774         $user3 = self::getDataGenerator()->create_user();
775         $user4 = self::getDataGenerator()->create_user();
777         // The person doing the search.
778         $this->setUser($user1);
780         // Only self-conversation created.
781         $this->assertCount(1, \core_message\api::get_conversations($user1->id));
783         // Create some conversations for user1.
784         $time = 1;
785         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
786         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
787         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
788         $messageid1 = $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
790         $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
791         $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
792         $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
793         $messageid2 = $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
795         $this->send_fake_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?', 0, $time + 9);
796         $this->send_fake_message($user4, $user1, 'Yah brah, it\'s pretty rad.', 0, $time + 10);
797         $messageid3 = $this->send_fake_message($user1, $user4, 'Dope.', 0, $time + 11);
799         // Favourite the first 2 conversations for user1.
800         $convoids = [];
801         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
802         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]);
803         $user1context = context_user::instance($user1->id);
804         $service = \core_favourites\service_factory::get_service_for_user_context($user1context);
805         foreach ($convoids as $convoid) {
806             $service->create_favourite('core_message', 'message_conversations', $convoid, $user1context);
807         }
809         // We should have 4 conversations.
810         // Consider first conversations is self-conversation.
811         $this->assertCount(4, \core_message\api::get_conversations($user1->id));
813         // And 3 favourited conversations (self-conversation included).
814         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, true);
815         $this->assertCount(3, $conversations);
816         $conversations = \core_message\api::get_conversations(
817             $user1->id,
818             0,
819             20,
820             \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF,
821             true
822         );
823         $this->assertCount(1, $conversations);
824     }
826     /**
827      * Tests retrieving favourite conversations with a limit and offset to ensure pagination works correctly.
828      */
829     public function test_get_favourite_conversations_limit_offset() {
830         // Create some users.
831         $user1 = self::getDataGenerator()->create_user();
832         $user2 = self::getDataGenerator()->create_user();
833         $user3 = self::getDataGenerator()->create_user();
834         $user4 = self::getDataGenerator()->create_user();
836         // The person doing the search.
837         $this->setUser($user1);
839         // Only self-conversation created.
840         $this->assertCount(1, \core_message\api::get_conversations($user1->id));
842         // Create some conversations for user1.
843         $time = 1;
844         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
845         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
846         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
847         $messageid1 = $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
849         $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
850         $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
851         $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
852         $messageid2 = $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
854         $this->send_fake_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?', 0, $time + 9);
855         $this->send_fake_message($user4, $user1, 'Yah brah, it\'s pretty rad.', 0, $time + 10);
856         $messageid3 = $this->send_fake_message($user1, $user4, 'Dope.', 0, $time + 11);
858         // Favourite the all conversations for user1.
859         $convoids = [];
860         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
861         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]);
862         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user4->id]);
863         $user1context = context_user::instance($user1->id);
864         $service = \core_favourites\service_factory::get_service_for_user_context($user1context);
865         foreach ($convoids as $convoid) {
866             $service->create_favourite('core_message', 'message_conversations', $convoid, $user1context);
867         }
869         // Consider first conversations is self-conversation.
870         // Get all records, using offset 0 and large limit.
871         $this->assertCount(4, \core_message\api::get_conversations($user1->id, 0, 20, null, true));
873         // Now, get 10 conversations starting at the second record. We should see 2 conversations.
874         $this->assertCount(3, \core_message\api::get_conversations($user1->id, 1, 10, null, true));
876         // Now, try to get favourited conversations using an invalid offset.
877         $this->assertCount(0, \core_message\api::get_conversations($user1->id, 5, 10, null, true));
878     }
880     /**
881      * Tests retrieving favourite conversations when a conversation contains a deleted user.
882      */
883     public function test_get_favourite_conversations_with_deleted_user() {
884         // Create some users.
885         $user1 = self::getDataGenerator()->create_user();
886         $user2 = self::getDataGenerator()->create_user();
887         $user3 = self::getDataGenerator()->create_user();
889         // Send some messages back and forth, have some different conversations with different users.
890         $time = 1;
891         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
892         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
893         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
894         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
896         $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
897         $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
898         $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
899         $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
901         // Favourite the all conversations for user1.
902         $convoids = [];
903         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
904         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]);
905         $user1context = context_user::instance($user1->id);
906         $service = \core_favourites\service_factory::get_service_for_user_context($user1context);
907         foreach ($convoids as $convoid) {
908             $service->create_favourite('core_message', 'message_conversations', $convoid, $user1context);
909         }
911         // Delete the second user.
912         delete_user($user2);
914         // Retrieve the conversations.
915         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, true);
917         // We should have both conversations, despite the other user being soft-deleted.
918         // Consider first conversations is self-conversation.
919         $this->assertCount(3, $conversations);
921         // Confirm the conversation is from the non-deleted user.
922         $conversation = reset($conversations);
923         $this->assertEquals($convoids[1], $conversation->id);
924     }
926     /**
927      * Test confirming that conversations can be marked as favourites.
928      */
929     public function test_set_favourite_conversation() {
930         // Create some users.
931         $user1 = self::getDataGenerator()->create_user();
932         $user2 = self::getDataGenerator()->create_user();
933         $user3 = self::getDataGenerator()->create_user();
935         // Send some messages back and forth, have some different conversations with different users.
936         $time = 1;
937         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
938         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
939         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
940         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
942         $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
943         $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
944         $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
945         $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
947         // Favourite the first conversation as user 1.
948         $conversationid1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
949         $favourite = \core_message\api::set_favourite_conversation($conversationid1, $user1->id);
951         // Verify we have two favourite conversations a user 1.
952         // Consider first conversations is self-conversation.
953         $this->assertCount(2, \core_message\api::get_conversations($user1->id, 0, 20, null, true));
955         // Verify we have only one favourite as user2, despite being a member in that conversation.
956         // Consider first conversations is self-conversation.
957         $this->assertCount(1, \core_message\api::get_conversations($user2->id, 0, 20, null, true));
959         // Try to favourite the same conversation again should just return the existing favourite.
960         $repeatresult = \core_message\api::set_favourite_conversation($conversationid1, $user1->id);
961         $this->assertEquals($favourite->id, $repeatresult->id);
962     }
964     /**
965      * Test verifying that trying to mark a non-existent conversation as a favourite, results in an exception.
966      */
967     public function test_set_favourite_conversation_nonexistent_conversation() {
968         // Create some users.
969         $user1 = self::getDataGenerator()->create_user();
970         // Try to favourite a non-existent conversation.
971         $this->expectException(\moodle_exception::class);
972         \core_message\api::set_favourite_conversation(0, $user1->id);
973     }
975     /**
976      * Test verifying that a conversation cannot be marked as favourite unless the user is a member of that conversation.
977      */
978     public function test_set_favourite_conversation_non_member() {
979         // Create some users.
980         $user1 = self::getDataGenerator()->create_user();
981         $user2 = self::getDataGenerator()->create_user();
982         $user3 = self::getDataGenerator()->create_user();
984         // Send some messages back and forth, have some different conversations with different users.
985         $time = 1;
986         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
987         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
988         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
989         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
991         $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
992         $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
993         $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
994         $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
996         // Try to favourite the first conversation as user 3, who is not a member.
997         $conversationid1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
998         $this->expectException(\moodle_exception::class);
999         \core_message\api::set_favourite_conversation($conversationid1, $user3->id);
1000     }
1002     /**
1003      * Test confirming that those conversations marked as favourites can be unfavourited.
1004      */
1005     public function test_unset_favourite_conversation() {
1006         // Create some users.
1007         $user1 = self::getDataGenerator()->create_user();
1008         $user2 = self::getDataGenerator()->create_user();
1009         $user3 = self::getDataGenerator()->create_user();
1011         // Send some messages back and forth, have some different conversations with different users.
1012         $time = 1;
1013         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
1014         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
1015         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
1016         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
1018         $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
1019         $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
1020         $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
1021         $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
1023         // Favourite the first conversation as user 1 and the second as user 3.
1024         $conversationid1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
1025         $conversationid2 = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]);
1026         \core_message\api::set_favourite_conversation($conversationid1, $user1->id);
1027         \core_message\api::set_favourite_conversation($conversationid2, $user3->id);
1029         // Verify we have two favourite conversations for both user 1 and user 3, counting self conversations.
1030         $this->assertCount(2, \core_message\api::get_conversations($user1->id, 0, 20, null, true));
1031         $this->assertCount(2, \core_message\api::get_conversations($user3->id, 0, 20, null, true));
1033         // Now unfavourite the conversation as user 1.
1034         \core_message\api::unset_favourite_conversation($conversationid1, $user1->id);
1036         // Verify we have two favourite conversations user 3 only, and one for user1, counting self conversations.
1037         $this->assertCount(2, \core_message\api::get_conversations($user3->id, 0, 20, null, true));
1038         $this->assertCount(1, \core_message\api::get_conversations($user1->id, 0, 20, null, true));
1040         // Try to favourite the same conversation again as user 1.
1041         $this->expectException(\moodle_exception::class);
1042         \core_message\api::unset_favourite_conversation($conversationid1, $user1->id);
1043     }
1045     /**
1046      * Test verifying that a valid conversation cannot be unset as a favourite if it's not marked as a favourite.
1047      */
1048     public function test_unset_favourite_conversation_not_favourite() {
1049         // Create some users.
1050         $user1 = self::getDataGenerator()->create_user();
1051         $user2 = self::getDataGenerator()->create_user();
1053         // Send some messages back and forth, have some different conversations with different users.
1054         $time = 1;
1055         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
1056         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
1057         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
1058         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
1060         // Now try to unfavourite the conversation as user 1.
1061         $conversationid1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
1062         $this->expectException(\moodle_exception::class);
1063         \core_message\api::unset_favourite_conversation($conversationid1, $user1->id);
1064     }
1066     /**
1067      * Test verifying that a non-existent conversation cannot be unset as a favourite.
1068      */
1069     public function test_unset_favourite_conversation_non_existent_conversation() {
1070         // Create some users.
1071         $user1 = self::getDataGenerator()->create_user();
1073         // Now try to unfavourite the conversation as user 1.
1074         $this->expectException(\moodle_exception::class);
1075         \core_message\api::unset_favourite_conversation(0, $user1->id);
1076     }
1078     /**
1079      * Helper to seed the database with initial state.
1080      */
1081     protected function create_conversation_test_data() {
1082         // Create some users.
1083         $user1 = self::getDataGenerator()->create_user();
1084         $user2 = self::getDataGenerator()->create_user();
1085         $user3 = self::getDataGenerator()->create_user();
1086         $user4 = self::getDataGenerator()->create_user();
1088         $time = 1;
1090         // Create some conversations. We want:
1091         // 1) At least one of each type (group, individual) of which user1 IS a member and DID send the most recent message.
1092         // 2) At least one of each type (group, individual) of which user1 IS a member and DID NOT send the most recent message.
1093         // 3) At least one of each type (group, individual) of which user1 IS NOT a member.
1094         // 4) At least two group conversation having 0 messages, of which user1 IS a member (To confirm conversationid ordering).
1095         // 5) At least one group conversation having 0 messages, of which user1 IS NOT a member.
1097         // Individual conversation, user1 is a member, last message from other user.
1098         $ic1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1099             [$user1->id, $user2->id]);
1100         testhelper::send_fake_message_to_conversation($user1, $ic1->id, 'Message 1', $time);
1101         testhelper::send_fake_message_to_conversation($user2, $ic1->id, 'Message 2', $time + 1);
1103         // Individual conversation, user1 is a member, last message from user1.
1104         $ic2 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1105             [$user1->id, $user3->id]);
1106         testhelper::send_fake_message_to_conversation($user3, $ic2->id, 'Message 3', $time + 2);
1107         testhelper::send_fake_message_to_conversation($user1, $ic2->id, 'Message 4', $time + 3);
1109         // Individual conversation, user1 is not a member.
1110         $ic3 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1111             [$user2->id, $user3->id]);
1112         testhelper::send_fake_message_to_conversation($user2, $ic3->id, 'Message 5', $time + 4);
1113         testhelper::send_fake_message_to_conversation($user3, $ic3->id, 'Message 6', $time + 5);
1115         // Group conversation, user1 is not a member.
1116         $gc1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1117             [$user2->id, $user3->id, $user4->id], 'Project discussions');
1118         testhelper::send_fake_message_to_conversation($user2, $gc1->id, 'Message 7', $time + 6);
1119         testhelper::send_fake_message_to_conversation($user4, $gc1->id, 'Message 8', $time + 7);
1121         // Group conversation, user1 is a member, last message from another user.
1122         $gc2 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1123             [$user1->id, $user3->id, $user4->id], 'Group chat');
1124         testhelper::send_fake_message_to_conversation($user1, $gc2->id, 'Message 9', $time + 8);
1125         testhelper::send_fake_message_to_conversation($user3, $gc2->id, 'Message 10', $time + 9);
1126         testhelper::send_fake_message_to_conversation($user4, $gc2->id, 'Message 11', $time + 10);
1128         // Group conversation, user1 is a member, last message from user1.
1129         $gc3 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1130             [$user1->id, $user2->id, $user3->id, $user4->id], 'Group chat again!');
1131         testhelper::send_fake_message_to_conversation($user4, $gc3->id, 'Message 12', $time + 11);
1132         testhelper::send_fake_message_to_conversation($user3, $gc3->id, 'Message 13', $time + 12);
1133         testhelper::send_fake_message_to_conversation($user1, $gc3->id, 'Message 14', $time + 13);
1135         // Empty group conversations (x2), user1 is a member.
1136         $gc4 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1137             [$user1->id, $user2->id, $user3->id], 'Empty group');
1138         $gc5 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1139             [$user1->id, $user2->id, $user4->id], 'Another empty group');
1141         // Empty group conversation, user1 is NOT a member.
1142         $gc6 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1143             [$user2->id, $user3->id, $user4->id], 'Empty group 3');
1145         return [$user1, $user2, $user3, $user4, $ic1, $ic2, $ic3, $gc1, $gc2, $gc3, $gc4, $gc5, $gc6];
1146     }
1148     /**
1149      * Test verifying get_conversations when no limits, offsets, type filters or favourite restrictions are used.
1150      */
1151     public function test_get_conversations_no_restrictions() {
1152         global $DB;
1154         $user1 = self::getDataGenerator()->create_user();
1155         // Self-conversation should exists.
1156         $this->assertCount(1, \core_message\api::get_conversations($user1->id));
1158         // Get a bunch of conversations, some group, some individual and in different states.
1159         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1160             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1162         // Get all conversations for user1.
1163         $conversations = core_message\api::get_conversations($user1->id);
1165         // Verify there are 2 individual conversation, 2 group conversations, 2 empty group conversations,
1166         // and a self-conversation.
1167         // The conversations with the most recent messages should be listed first, followed by the empty
1168         // conversations, with the most recently created first.
1169         $this->assertCount(7, $conversations);
1170         $typecounts  = array_count_values(array_column($conversations, 'type'));
1171         $this->assertEquals(2, $typecounts[1]);
1172         $this->assertEquals(4, $typecounts[2]);
1173         $this->assertEquals(1, $typecounts[3]);
1175         // Those conversations having messages should be listed after self-conversation, ordered by most recent message time.
1176         $this->assertEquals($gc3->id, $conversations[0]->id);
1177         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $conversations[0]->type);
1178         $this->assertFalse($conversations[1]->isfavourite);
1179         $this->assertCount(1, $conversations[0]->members);
1180         $this->assertEquals(4, $conversations[0]->membercount);
1181         $this->assertCount(1, $conversations[0]->messages);
1182         $message = $DB->get_record('messages', ['id' => $conversations[0]->messages[0]->id]);
1183         $expectedmessagetext = message_format_message_text($message);
1184         $this->assertEquals($expectedmessagetext, $conversations[0]->messages[0]->text);
1185         $this->assertEquals($user1->id, $conversations[0]->messages[0]->useridfrom);
1187         $this->assertEquals($gc2->id, $conversations[1]->id);
1188         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $conversations[1]->type);
1189         $this->assertFalse($conversations[1]->isfavourite);
1190         $this->assertCount(1, $conversations[1]->members);
1191         $this->assertEquals(3, $conversations[1]->membercount);
1192         $this->assertCount(1, $conversations[1]->messages);
1193         $message = $DB->get_record('messages', ['id' => $conversations[1]->messages[0]->id]);
1194         $expectedmessagetext = message_format_message_text($message);
1195         $this->assertEquals($expectedmessagetext, $conversations[1]->messages[0]->text);
1196         $this->assertEquals($user4->id, $conversations[1]->messages[0]->useridfrom);
1198         $this->assertEquals($ic2->id, $conversations[2]->id);
1199         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $conversations[2]->type);
1200         $this->assertFalse($conversations[2]->isfavourite);
1201         $this->assertCount(1, $conversations[2]->members);
1202         $this->assertEquals($user3->id, $conversations[2]->members[$user3->id]->id);
1203         $this->assertEquals(2, $conversations[2]->membercount);
1204         $this->assertCount(1, $conversations[2]->messages);
1205         $message = $DB->get_record('messages', ['id' => $conversations[2]->messages[0]->id]);
1206         $expectedmessagetext = message_format_message_text($message);
1207         $this->assertEquals($expectedmessagetext, $conversations[2]->messages[0]->text);
1208         $this->assertEquals($user1->id, $conversations[2]->messages[0]->useridfrom);
1210         $this->assertEquals($ic1->id, $conversations[3]->id);
1211         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $conversations[3]->type);
1212         $this->assertFalse($conversations[3]->isfavourite);
1213         $this->assertCount(1, $conversations[3]->members);
1214         $this->assertEquals(2, $conversations[3]->membercount);
1215         $this->assertCount(1, $conversations[3]->messages);
1216         $message = $DB->get_record('messages', ['id' => $conversations[3]->messages[0]->id]);
1217         $expectedmessagetext = message_format_message_text($message);
1218         $this->assertEquals($expectedmessagetext, $conversations[3]->messages[0]->text);
1219         $this->assertEquals($user2->id, $conversations[3]->messages[0]->useridfrom);
1221         // Of the groups without messages, we expect to see the most recently created first.
1222         $this->assertEquals($gc5->id, $conversations[4]->id);
1223         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $conversations[4]->type);
1224         $this->assertFalse($conversations[4]->isfavourite);
1225         $this->assertCount(0, $conversations[4]->members); // No members returned, because no recent messages exist.
1226         $this->assertEquals(3, $conversations[4]->membercount);
1227         $this->assertEmpty($conversations[4]->messages);
1229         $this->assertEquals($gc4->id, $conversations[5]->id);
1230         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $conversations[5]->type);
1231         $this->assertFalse($conversations[5]->isfavourite);
1232         $this->assertCount(0, $conversations[5]->members);
1233         $this->assertEquals(3, $conversations[5]->membercount);
1234         $this->assertEmpty($conversations[5]->messages);
1236         // Verify format of the return structure.
1237         foreach ($conversations as $conv) {
1238             $this->assertObjectHasAttribute('id', $conv);
1239             $this->assertObjectHasAttribute('name', $conv);
1240             $this->assertObjectHasAttribute('subname', $conv);
1241             $this->assertObjectHasAttribute('imageurl', $conv);
1242             $this->assertObjectHasAttribute('type', $conv);
1243             $this->assertObjectHasAttribute('isfavourite', $conv);
1244             $this->assertObjectHasAttribute('membercount', $conv);
1245             $this->assertObjectHasAttribute('isread', $conv);
1246             $this->assertObjectHasAttribute('unreadcount', $conv);
1247             $this->assertObjectHasAttribute('members', $conv);
1248             foreach ($conv->members as $member) {
1249                 $this->assertObjectHasAttribute('id', $member);
1250                 $this->assertObjectHasAttribute('fullname', $member);
1251                 $this->assertObjectHasAttribute('profileimageurl', $member);
1252                 $this->assertObjectHasAttribute('profileimageurlsmall', $member);
1253                 $this->assertObjectHasAttribute('isonline', $member);
1254                 $this->assertObjectHasAttribute('showonlinestatus', $member);
1255                 $this->assertObjectHasAttribute('isblocked', $member);
1256                 $this->assertObjectHasAttribute('iscontact', $member);
1257                 $this->assertObjectHasAttribute('isdeleted', $member);
1258                 $this->assertObjectHasAttribute('canmessage', $member);
1259                 $this->assertObjectHasAttribute('requirescontact', $member);
1260                 $this->assertObjectHasAttribute('contactrequests', $member);
1261             }
1262             $this->assertObjectHasAttribute('messages', $conv);
1263             foreach ($conv->messages as $message) {
1264                 $this->assertObjectHasAttribute('id', $message);
1265                 $this->assertObjectHasAttribute('useridfrom', $message);
1266                 $this->assertObjectHasAttribute('text', $message);
1267                 $this->assertObjectHasAttribute('timecreated', $message);
1268             }
1269         }
1270     }
1272     /**
1273      * Test verifying that html format messages are supported, and that message_format_message_text() is being called appropriately.
1274      */
1275     public function test_get_conversations_message_format() {
1276         global $DB;
1277         // Create some users.
1278         $user1 = self::getDataGenerator()->create_user();
1279         $user2 = self::getDataGenerator()->create_user();
1281         // Create conversation.
1282         $conversation = \core_message\api::create_conversation(
1283             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1284             [$user1->id, $user2->id]
1285         );
1287         // Send some messages back and forth.
1288         $time = 1;
1289         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 1);
1290         $mid = testhelper::send_fake_message_to_conversation($user1, $conversation->id, '<a href="#">A link</a>', $time + 2);
1292         // Verify the format of the html message.
1293         $message = $DB->get_record('messages', ['id' => $mid]);
1294         $expectedmessagetext = message_format_message_text($message);
1295         $conversations = \core_message\api::get_conversations($user1->id);
1296         $messages = $conversations[0]->messages;
1297         $this->assertEquals($expectedmessagetext, $messages[0]->text);
1298     }
1300     /**
1301      * Test verifying get_conversations identifies if a conversation is muted or not.
1302      */
1303     public function test_get_conversations_some_muted() {
1304         // Create some users.
1305         $user1 = self::getDataGenerator()->create_user();
1306         $user2 = self::getDataGenerator()->create_user();
1307         $user3 = self::getDataGenerator()->create_user();
1309         $conversation1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1310             [$user1->id, $user2->id]);
1311         testhelper::send_fake_message_to_conversation($user1, $conversation1->id, 'Message 1');
1312         testhelper::send_fake_message_to_conversation($user2, $conversation1->id, 'Message 2');
1313         \core_message\api::mute_conversation($user1->id, $conversation1->id);
1315         $conversation2 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1316             [$user1->id, $user3->id]);
1317         testhelper::send_fake_message_to_conversation($user1, $conversation2->id, 'Message 1');
1318         testhelper::send_fake_message_to_conversation($user2, $conversation2->id, 'Message 2');
1320         $conversation3 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1321             [$user1->id, $user2->id]);
1322         \core_message\api::mute_conversation($user1->id, $conversation3->id);
1324         $conversation4 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1325             [$user1->id, $user3->id]);
1327         $conversations = \core_message\api::get_conversations($user1->id);
1329         usort($conversations, function($first, $second){
1330             return $first->id > $second->id;
1331         });
1333         // Consider first conversations is self-conversation.
1334         $selfconversation = array_shift($conversations);
1335         $conv1 = array_shift($conversations);
1336         $conv2 = array_shift($conversations);
1337         $conv3 = array_shift($conversations);
1338         $conv4 = array_shift($conversations);
1340         $this->assertTrue($conv1->ismuted);
1341         $this->assertFalse($conv2->ismuted);
1342         $this->assertTrue($conv3->ismuted);
1343         $this->assertFalse($conv4->ismuted);
1344     }
1346     /**
1347      * Tests retrieving conversations with a limit and offset to ensure pagination works correctly.
1348      */
1349     public function test_get_conversations_limit_offset() {
1350         // Get a bunch of conversations, some group, some individual and in different states.
1351         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1352             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1354         // Get all conversations for user1, limited to 1 result.
1355         $conversations = core_message\api::get_conversations($user1->id, 0, 1);
1357         // Verify the first conversation.
1358         $this->assertCount(1, $conversations);
1359         $conversation = array_shift($conversations);
1360         $this->assertEquals($conversation->id, $gc3->id);
1362         // Verify the next conversation.
1363         $conversations = \core_message\api::get_conversations($user1->id, 1, 1);
1364         $this->assertCount(1, $conversations);
1365         $this->assertEquals($gc2->id, $conversations[0]->id);
1367         // Verify the next conversation.
1368         $conversations = \core_message\api::get_conversations($user1->id, 2, 1);
1369         $this->assertCount(1, $conversations);
1370         $this->assertEquals($ic2->id, $conversations[0]->id);
1372         // Skip one and get both empty conversations.
1373         $conversations = \core_message\api::get_conversations($user1->id, 4, 2);
1374         $this->assertCount(2, $conversations);
1375         $this->assertEquals($gc5->id, $conversations[0]->id);
1376         $this->assertEmpty($conversations[0]->messages);
1377         $this->assertEquals($gc4->id, $conversations[1]->id);
1378         $this->assertEmpty($conversations[1]->messages);
1380         // Ask for an offset that doesn't exist and verify no conversations are returned.
1381         $conversations = \core_message\api::get_conversations($user1->id, 10, 1);
1382         $this->assertCount(0, $conversations);
1383     }
1385     /**
1386      * Test verifying the type filtering behaviour of the
1387      */
1388     public function test_get_conversations_type_filter() {
1389         // Get a bunch of conversations, some group, some individual and in different states.
1390         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1391             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1393         // Verify we can ask for only individual conversations.
1394         $conversations = \core_message\api::get_conversations($user1->id, 0, 20,
1395             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL);
1396         $this->assertCount(2, $conversations);
1398         // Verify we can ask for only group conversations.
1399         $conversations = \core_message\api::get_conversations($user1->id, 0, 20,
1400             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP);
1401         $this->assertCount(4, $conversations);
1403         // Verify an exception is thrown if an unrecognized type is specified.
1404         $this->expectException(\moodle_exception::class);
1405         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, 0);
1406     }
1408     /**
1409      * Tests retrieving conversations when a 'self' conversation exists.
1410      */
1411     public function test_get_conversations_self_conversations() {
1412         global $DB;
1414         // Create a conversation between one user and themself.
1415         $user1 = self::getDataGenerator()->create_user();
1416         $user2 = self::getDataGenerator()->create_user();
1417         $user3 = self::getDataGenerator()->create_user();
1418         $user4 = self::getDataGenerator()->create_user();
1420         // Create some individual conversations.
1421         $ic1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1422             [$user1->id, $user2->id]);
1423         $ic2 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1424             [$user1->id, $user3->id]);
1425         testhelper::send_fake_message_to_conversation($user1, $ic1->id, 'Message from user1 to user2');
1427         // Get some self-conversations.
1428         $sc1 = \core_message\api::get_self_conversation($user1->id);
1429         $sc4 = \core_message\api::get_self_conversation($user4->id);
1430         testhelper::send_fake_message_to_conversation($user1, $sc1->id, 'Test message to self 1!');
1432         // Verify we are in a 'self' conversation state.
1433         $members = $DB->get_records('message_conversation_members', ['conversationid' => $sc1->id]);
1434         $this->assertCount(1, $members);
1435         $member = array_pop($members);
1436         $this->assertEquals($user1->id, $member->userid);
1438         // Verify the self-conversations are returned by the method.
1439         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF);
1440         $this->assertCount(1, $conversations);
1441         $conversation = array_pop($conversations);
1442         $this->assertEquals($conversation->id, $sc1->id);
1444         $conversations = \core_message\api::get_conversations($user4->id);
1445         // The self-conversation.
1446         $this->assertCount(1, $conversations);
1448         // Get only private conversations for user1 (empty conversations, like $ic2, are not returned).
1449         $conversations = \core_message\api::get_conversations($user1->id, 0, 20,
1450             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL);
1451         $this->assertCount(1, $conversations);
1453         // Merge self with private conversations for user1.
1454         $conversations = \core_message\api::get_conversations($user1->id, 0, 20,
1455             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, null, true);
1456         $this->assertCount(2, $conversations);
1458         // Get only private conversations for user2.
1459         $conversations = \core_message\api::get_conversations($user2->id, 0, 20,
1460             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL);
1461         $this->assertCount(1, $conversations);
1463         // Merge self with private conversations for user2.
1464         $conversations = \core_message\api::get_conversations($user2->id, 0, 20,
1465             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, null, true);
1466         $this->assertCount(2, $conversations);
1467     }
1469     /**
1470      * Tests retrieving conversations when a conversation contains a deleted user.
1471      */
1472     public function test_get_conversations_with_deleted_user() {
1473         // Get a bunch of conversations, some group, some individual and in different states.
1474         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1475             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1477         // Delete the second user and retrieve the conversations.
1478         // We should have 6 still, as conversations with soft-deleted users are still returned.
1479         // Group conversations are also present, albeit with less members.
1480         delete_user($user2);
1481         // This is to confirm an exception is not thrown when a user AND the user context is deleted.
1482         // We no longer delete the user context, but historically we did.
1483         context_helper::delete_instance(CONTEXT_USER, $user2->id);
1484         $conversations = \core_message\api::get_conversations($user1->id);
1485         // Consider there's a self-conversation (the last one).
1486         $this->assertCount(7, $conversations);
1487         $this->assertEquals($gc3->id, $conversations[0]->id);
1488         $this->assertcount(1, $conversations[0]->members);
1489         $this->assertEquals($gc2->id, $conversations[1]->id);
1490         $this->assertcount(1, $conversations[1]->members);
1491         $this->assertEquals($ic2->id, $conversations[2]->id);
1492         $this->assertEquals($ic1->id, $conversations[3]->id);
1493         $this->assertEquals($gc5->id, $conversations[4]->id);
1494         $this->assertEquals($gc4->id, $conversations[5]->id);
1496         // Delete a user from a group conversation where that user had sent the most recent message.
1497         // This user will still be present in the members array, as will the message in the messages array.
1498         delete_user($user4);
1499         $conversations = \core_message\api::get_conversations($user1->id);
1501         // Consider there's a self-conversation (the last one).
1502         $this->assertCount(7, $conversations);
1503         $this->assertEquals($gc2->id, $conversations[1]->id);
1504         $this->assertcount(1, $conversations[1]->members);
1505         $this->assertEquals($user4->id, $conversations[1]->members[$user4->id]->id);
1506         $this->assertcount(1, $conversations[1]->messages);
1507         $this->assertEquals($user4->id, $conversations[1]->messages[0]->useridfrom);
1509         // Delete the third user and retrieve the conversations.
1510         // We should have 6 still, as conversations with soft-deleted users are still returned.
1511         // Group conversations are also present, albeit with less members.
1512         delete_user($user3);
1513         $conversations = \core_message\api::get_conversations($user1->id);
1514         // Consider there's a self-conversation (the last one).
1515         $this->assertCount(7, $conversations);
1516         $this->assertEquals($gc3->id, $conversations[0]->id);
1517         $this->assertcount(1, $conversations[0]->members);
1518         $this->assertEquals($gc2->id, $conversations[1]->id);
1519         $this->assertcount(1, $conversations[1]->members);
1520         $this->assertEquals($ic2->id, $conversations[2]->id);
1521         $this->assertEquals($ic1->id, $conversations[3]->id);
1522         $this->assertEquals($gc5->id, $conversations[4]->id);
1523         $this->assertEquals($gc4->id, $conversations[5]->id);
1524     }
1526     /**
1527      * Test confirming the behaviour of get_conversations() when users delete all messages.
1528      */
1529     public function test_get_conversations_deleted_messages() {
1530         // Get a bunch of conversations, some group, some individual and in different states.
1531         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1532             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1534         $conversations = \core_message\api::get_conversations($user1->id);
1535         // Consider first conversations is self-conversation.
1536         $this->assertCount(7, $conversations);
1538         // Delete all messages from a group conversation the user is in - it should be returned.
1539         $this->assertTrue(\core_message\api::is_user_in_conversation($user1->id, $gc2->id));
1540         $convmessages = \core_message\api::get_conversation_messages($user1->id, $gc2->id);
1541         $messages = $convmessages['messages'];
1542         foreach ($messages as $message) {
1543             \core_message\api::delete_message($user1->id, $message->id);
1544         }
1545         $conversations = \core_message\api::get_conversations($user1->id);
1546         // Consider first conversations is self-conversation.
1547         $this->assertCount(7, $conversations);
1548         $this->assertContains($gc2->id, array_column($conversations, 'id'));
1550         // Delete all messages from an individual conversation the user is in - it should not be returned.
1551         $this->assertTrue(\core_message\api::is_user_in_conversation($user1->id, $ic1->id));
1552         $convmessages = \core_message\api::get_conversation_messages($user1->id, $ic1->id);
1553         $messages = $convmessages['messages'];
1554         foreach ($messages as $message) {
1555             \core_message\api::delete_message($user1->id, $message->id);
1556         }
1557         $conversations = \core_message\api::get_conversations($user1->id);
1558         // Consider first conversations is self-conversation.
1559         $this->assertCount(6, $conversations);
1560         $this->assertNotContains($ic1->id, array_column($conversations, 'id'));
1561     }
1563     /**
1564      * Test verifying the behaviour of get_conversations() when fetching favourite conversations with only a single
1565      * favourite.
1566      */
1567     public function test_get_conversations_favourite_conversations_single() {
1568         // Get a bunch of conversations, some group, some individual and in different states.
1569         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1570             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1572         // Mark a single conversation as favourites.
1573         \core_message\api::set_favourite_conversation($ic2->id, $user1->id);
1575         // Get the conversation, first with no restrictions, confirming the favourite status of the conversations.
1576         $conversations = \core_message\api::get_conversations($user1->id);
1577         // Consider there is a self-conversation.
1578         $selfconversation = \core_message\api::get_self_conversation($user1->id);
1579         $this->assertCount(7, $conversations);
1580         foreach ($conversations as $conv) {
1581             if (in_array($conv->id, [$ic2->id, $selfconversation->id])) {
1582                 $this->assertTrue($conv->isfavourite);
1583             } else {
1584                 $this->assertFalse($conv->isfavourite);
1585             }
1586         }
1588         // Now, get ONLY favourite conversations (including self-conversation).
1589         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, true);
1590         $this->assertCount(2, $conversations);
1591         foreach ($conversations as $conv) {
1592             if ($conv->type != \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF) {
1593                 $this->assertTrue($conv->isfavourite);
1594                 $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $conv->type);
1595                 $this->assertEquals($ic2->id, $conv->id);
1596             }
1597         }
1599         // Now, try ONLY favourites of type 'group'.
1600         $conversations = \core_message\api::get_conversations($user1->id, 0, 20,
1601             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, true);
1602         $this->assertEmpty($conversations);
1604         // And NO favourite conversations.
1605         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, false);
1606         $this->assertCount(5, $conversations);
1607         foreach ($conversations as $conv) {
1608             $this->assertFalse($conv->isfavourite);
1609             $this->assertNotEquals($ic2, $conv->id);
1610         }
1611     }
1613     /**
1614      * Test verifying the behaviour of get_conversations() when fetching favourite conversations.
1615      */
1616     public function test_get_conversations_favourite_conversations() {
1617         // Get a bunch of conversations, some group, some individual and in different states.
1618         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1619             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1621         // Try to get ONLY favourite conversations, when only self-conversation exist.
1622         $this->assertCount(1, \core_message\api::get_conversations($user1->id, 0, 20, null, true));
1624         // Unstar self-conversation.
1625         $selfconversation = \core_message\api::get_self_conversation($user1->id);
1626         \core_message\api::unset_favourite_conversation($selfconversation->id, $user1->id);
1628         // Try to get ONLY favourite conversations, when no favourites exist.
1629         $this->assertEquals([], \core_message\api::get_conversations($user1->id, 0, 20, null, true));
1631         // Try to get NO favourite conversations, when no favourites exist.
1632         $this->assertCount(7, \core_message\api::get_conversations($user1->id, 0, 20, null, false));
1634         // Mark a few conversations as favourites.
1635         \core_message\api::set_favourite_conversation($ic1->id, $user1->id);
1636         \core_message\api::set_favourite_conversation($gc2->id, $user1->id);
1637         \core_message\api::set_favourite_conversation($gc5->id, $user1->id);
1638         $favouriteids = [$ic1->id, $gc2->id, $gc5->id];
1640         // Get the conversations, first with no restrictions, confirming the favourite status of the conversations.
1641         $conversations = \core_message\api::get_conversations($user1->id);
1642         $this->assertCount(7, $conversations);
1643         foreach ($conversations as $conv) {
1644             if (in_array($conv->id, $favouriteids)) {
1645                 $this->assertTrue($conv->isfavourite);
1646             } else {
1647                 $this->assertFalse($conv->isfavourite);
1648             }
1649         }
1651         // Now, get ONLY favourite conversations.
1652         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, true);
1653         $this->assertCount(3, $conversations);
1654         foreach ($conversations as $conv) {
1655             $this->assertTrue($conv->isfavourite);
1656             $this->assertNotFalse(array_search($conv->id, $favouriteids));
1657         }
1659         // Now, try ONLY favourites of type 'group'.
1660         $conversations = \core_message\api::get_conversations($user1->id, 0, 20,
1661             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, true);
1662         $this->assertCount(2, $conversations);
1663         foreach ($conversations as $conv) {
1664             $this->assertTrue($conv->isfavourite);
1665             $this->assertNotFalse(array_search($conv->id, [$gc2->id, $gc5->id]));
1666         }
1668         // And NO favourite conversations.
1669         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, false);
1670         $this->assertCount(4, $conversations);
1671         foreach ($conversations as $conv) {
1672             $this->assertFalse($conv->isfavourite);
1673             $this->assertFalse(array_search($conv->id, $favouriteids));
1674         }
1675     }
1677     /**
1678      * Test verifying get_conversations when there are users in a group and/or individual conversation. The reason this
1679      * test is performed is because we do not need as much data for group conversations (saving DB calls), so we want
1680      * to confirm this happens.
1681      */
1682     public function test_get_conversations_user_in_group_and_individual_chat() {
1683         $this->resetAfterTest();
1685         $user1 = self::getDataGenerator()->create_user();
1686         $user2 = self::getDataGenerator()->create_user();
1687         $user3 = self::getDataGenerator()->create_user();
1689         $conversation = \core_message\api::create_conversation(
1690             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1691             [
1692                 $user1->id,
1693                 $user2->id
1694             ],
1695             'Individual conversation'
1696         );
1698         testhelper::send_fake_message_to_conversation($user1, $conversation->id);
1700         $conversation = \core_message\api::create_conversation(
1701             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1702             [
1703                 $user1->id,
1704                 $user2->id,
1705             ],
1706             'Group conversation'
1707         );
1709         testhelper::send_fake_message_to_conversation($user1, $conversation->id);
1711         \core_message\api::create_contact_request($user1->id, $user2->id);
1712         \core_message\api::create_contact_request($user1->id, $user3->id);
1714         $conversations = \core_message\api::get_conversations($user2->id);
1716         $groupconversation = array_shift($conversations);
1717         $individualconversation = array_shift($conversations);
1719         $this->assertEquals('Group conversation', $groupconversation->name);
1720         $this->assertEquals('Individual conversation', $individualconversation->name);
1722         $this->assertCount(1, $groupconversation->members);
1723         $this->assertCount(1, $individualconversation->members);
1725         $groupmember = reset($groupconversation->members);
1726         $this->assertNull($groupmember->requirescontact);
1727         $this->assertNull($groupmember->canmessage);
1728         $this->assertEmpty($groupmember->contactrequests);
1730         $individualmember = reset($individualconversation->members);
1731         $this->assertNotNull($individualmember->requirescontact);
1732         $this->assertNotNull($individualmember->canmessage);
1733         $this->assertNotEmpty($individualmember->contactrequests);
1734     }
1736     /**
1737      * Test verifying that group linked conversations are returned and contain a subname matching the course name.
1738      */
1739     public function test_get_conversations_group_linked() {
1740         global $CFG, $DB;
1742         // Create some users.
1743         $user1 = self::getDataGenerator()->create_user();
1744         $user2 = self::getDataGenerator()->create_user();
1745         $user3 = self::getDataGenerator()->create_user();
1747         $course1 = $this->getDataGenerator()->create_course();
1749         // Create a group with a linked conversation and a valid image.
1750         $this->setAdminUser();
1751         $this->getDataGenerator()->enrol_user($user1->id, $course1->id);
1752         $this->getDataGenerator()->enrol_user($user2->id, $course1->id);
1753         $this->getDataGenerator()->enrol_user($user3->id, $course1->id);
1754         $group1 = $this->getDataGenerator()->create_group([
1755             'courseid' => $course1->id,
1756             'enablemessaging' => 1,
1757             'picturepath' => $CFG->dirroot . '/lib/tests/fixtures/gd-logo.png'
1758         ]);
1760         // Add users to group1.
1761         $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user1->id));
1762         $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user2->id));
1764         // Verify the group with the image works as expected.
1765         $conversations = \core_message\api::get_conversations($user1->id);
1766         $this->assertEquals(2, $conversations[0]->membercount);
1767         $this->assertEquals($course1->shortname, $conversations[0]->subname);
1768         $groupimageurl = get_group_picture_url($group1, $group1->courseid, true);
1769         $this->assertEquals($groupimageurl, $conversations[0]->imageurl);
1771         // Create a group with a linked conversation and without any image.
1772         $group2 = $this->getDataGenerator()->create_group([
1773             'courseid' => $course1->id,
1774             'enablemessaging' => 1,
1775         ]);
1777         // Add users to group2.
1778         $this->getDataGenerator()->create_group_member(array('groupid' => $group2->id, 'userid' => $user2->id));
1779         $this->getDataGenerator()->create_group_member(array('groupid' => $group2->id, 'userid' => $user3->id));
1781         // Verify the group without any image works as expected too.
1782         $conversations = \core_message\api::get_conversations($user3->id);
1783         // Consider first conversations is self-conversation.
1784         $this->assertEquals(2, $conversations[0]->membercount);
1785         $this->assertEquals($course1->shortname, $conversations[0]->subname);
1786         $this->assertEquals('https://www.example.com/moodle/theme/image.php/_s/boost/core/1/g/g1', $conversations[0]->imageurl);
1788         // Now, disable the conversation linked to the group and verify it's no longer returned.
1789         $DB->set_field('message_conversations', 'enabled', 0, ['id' => $conversations[0]->id]);
1790         $conversations = \core_message\api::get_conversations($user3->id);
1791         $this->assertCount(1, $conversations);
1792     }
1794    /**
1795     * The data provider for get_conversations_mixed.
1796     *
1797     * This provides sets of data to for testing.
1798     * @return array
1799     */
1800    public function get_conversations_mixed_provider() {
1801        return array(
1802             'Test that conversations with messages contacts is correctly ordered.' => array(
1803                 'users' => array(
1804                     'user1',
1805                     'user2',
1806                     'user3',
1807                 ),
1808                 'contacts' => array(
1809                 ),
1810                 'messages' => array(
1811                     array(
1812                         'from'          => 'user1',
1813                         'to'            => 'user2',
1814                         'state'         => 'unread',
1815                         'subject'       => 'S1',
1816                     ),
1817                     array(
1818                         'from'          => 'user2',
1819                         'to'            => 'user1',
1820                         'state'         => 'unread',
1821                         'subject'       => 'S2',
1822                     ),
1823                     array(
1824                         'from'          => 'user1',
1825                         'to'            => 'user2',
1826                         'state'         => 'unread',
1827                         'timecreated'   => 0,
1828                         'subject'       => 'S3',
1829                     ),
1830                     array(
1831                         'from'          => 'user1',
1832                         'to'            => 'user3',
1833                         'state'         => 'read',
1834                         'timemodifier'  => 1,
1835                         'subject'       => 'S4',
1836                     ),
1837                     array(
1838                         'from'          => 'user3',
1839                         'to'            => 'user1',
1840                         'state'         => 'read',
1841                         'timemodifier'  => 1,
1842                         'subject'       => 'S5',
1843                     ),
1844                     array(
1845                         'from'          => 'user1',
1846                         'to'            => 'user3',
1847                         'state'         => 'read',
1848                         'timecreated'   => 0,
1849                         'subject'       => 'S6',
1850                     ),
1851                 ),
1852                 'expectations' => array(
1853                     'user1' => array(
1854                         // User1 has conversed most recently with user3. The most recent message is M5.
1855                         array(
1856                             'messageposition'   => 0,
1857                             'with'              => 'user3',
1858                             'subject'           => '<p>S5</p>',
1859                             'unreadcount'       => 0,
1860                         ),
1861                         // User1 has also conversed with user2. The most recent message is S2.
1862                         array(
1863                             'messageposition'   => 1,
1864                             'with'              => 'user2',
1865                             'subject'           => '<p>S2</p>',
1866                             'unreadcount'       => 1,
1867                         ),
1868                     ),
1869                     'user2' => array(
1870                         // User2 has only conversed with user1. Their most recent shared message was S2.
1871                         array(
1872                             'messageposition'   => 0,
1873                             'with'              => 'user1',
1874                             'subject'           => '<p>S2</p>',
1875                             'unreadcount'       => 2,
1876                         ),
1877                     ),
1878                     'user3' => array(
1879                         // User3 has only conversed with user1. Their most recent shared message was S5.
1880                         array(
1881                             'messageposition'   => 0,
1882                             'with'              => 'user1',
1883                             'subject'           => '<p>S5</p>',
1884                             'unreadcount'       => 0,
1885                         ),
1886                     ),
1887                 ),
1888             ),
1889             'Test conversations with a single user, where some messages are read and some are not.' => array(
1890                 'users' => array(
1891                     'user1',
1892                     'user2',
1893                 ),
1894                 'contacts' => array(
1895                 ),
1896                 'messages' => array(
1897                     array(
1898                         'from'          => 'user1',
1899                         'to'            => 'user2',
1900                         'state'         => 'read',
1901                         'subject'       => 'S1',
1902                     ),
1903                     array(
1904                         'from'          => 'user2',
1905                         'to'            => 'user1',
1906                         'state'         => 'read',
1907                         'subject'       => 'S2',
1908                     ),
1909                     array(
1910                         'from'          => 'user1',
1911                         'to'            => 'user2',
1912                         'state'         => 'unread',
1913                         'timemodifier'  => 1,
1914                         'subject'       => 'S3',
1915                     ),
1916                     array(
1917                         'from'          => 'user1',
1918                         'to'            => 'user2',
1919                         'state'         => 'unread',
1920                         'timemodifier'  => 1,
1921                         'subject'       => 'S4',
1922                     ),
1923                 ),
1924                 'expectations' => array(
1925                     // The most recent message between user1 and user2 was S4.
1926                     'user1' => array(
1927                         array(
1928                             'messageposition'   => 0,
1929                             'with'              => 'user2',
1930                             'subject'           => '<p>S4</p>',
1931                             'unreadcount'       => 0,
1932                         ),
1933                     ),
1934                     'user2' => array(
1935                         // The most recent message between user1 and user2 was S4.
1936                         array(
1937                             'messageposition'   => 0,
1938                             'with'              => 'user1',
1939                             'subject'           => '<p>S4</p>',
1940                             'unreadcount'       => 2,
1941                         ),
1942                     ),
1943                 ),
1944             ),
1945             'Test conversations with a single user, where some messages are read and some are not, and messages ' .
1946             'are out of order' => array(
1947             // This can happen through a combination of factors including multi-master DB replication with messages
1948             // read somehow (e.g. API).
1949                 'users' => array(
1950                     'user1',
1951                     'user2',
1952                 ),
1953                 'contacts' => array(
1954                 ),
1955                 'messages' => array(
1956                     array(
1957                         'from'          => 'user1',
1958                         'to'            => 'user2',
1959                         'state'         => 'read',
1960                         'subject'       => 'S1',
1961                         'timemodifier'  => 1,
1962                     ),
1963                     array(
1964                         'from'          => 'user2',
1965                         'to'            => 'user1',
1966                         'state'         => 'read',
1967                         'subject'       => 'S2',
1968                         'timemodifier'  => 2,
1969                     ),
1970                     array(
1971                         'from'          => 'user1',
1972                         'to'            => 'user2',
1973                         'state'         => 'unread',
1974                         'subject'       => 'S3',
1975                     ),
1976                     array(
1977                         'from'          => 'user1',
1978                         'to'            => 'user2',
1979                         'state'         => 'unread',
1980                         'subject'       => 'S4',
1981                     ),
1982                 ),
1983                 'expectations' => array(
1984                     // The most recent message between user1 and user2 was S2, even though later IDs have not been read.
1985                     'user1' => array(
1986                         array(
1987                             'messageposition'   => 0,
1988                             'with'              => 'user2',
1989                             'subject'           => '<p>S2</p>',
1990                             'unreadcount'       => 0,
1991                         ),
1992                     ),
1993                     'user2' => array(
1994                         array(
1995                             'messageposition'   => 0,
1996                             'with'              => 'user1',
1997                             'subject'           => '<p>S2</p>',
1998                             'unreadcount'       => 2
1999                         ),
2000                     ),
2001                 ),
2002             ),
2003             'Test unread message count is correct for both users' => array(
2004                 'users' => array(
2005                     'user1',
2006                     'user2',
2007                 ),
2008                 'contacts' => array(
2009                 ),
2010                 'messages' => array(
2011                     array(
2012                         'from'          => 'user1',
2013                         'to'            => 'user2',
2014                         'state'         => 'read',
2015                         'subject'       => 'S1',
2016                         'timemodifier'  => 1,
2017                     ),
2018                     array(
2019                         'from'          => 'user2',
2020                         'to'            => 'user1',
2021                         'state'         => 'read',
2022                         'subject'       => 'S2',
2023                         'timemodifier'  => 2,
2024                     ),
2025                     array(
2026                         'from'          => 'user1',
2027                         'to'            => 'user2',
2028                         'state'         => 'read',
2029                         'subject'       => 'S3',
2030                         'timemodifier'  => 3,
2031                     ),
2032                     array(
2033                         'from'          => 'user1',
2034                         'to'            => 'user2',
2035                         'state'         => 'read',
2036                         'subject'       => 'S4',
2037                         'timemodifier'  => 4,
2038                     ),
2039                     array(
2040                         'from'          => 'user1',
2041                         'to'            => 'user2',
2042                         'state'         => 'unread',
2043                         'subject'       => 'S5',
2044                         'timemodifier'  => 5,
2045                     ),
2046                     array(
2047                         'from'          => 'user2',
2048                         'to'            => 'user1',
2049                         'state'         => 'unread',
2050                         'subject'       => 'S6',
2051                         'timemodifier'  => 6,
2052                     ),
2053                     array(
2054                         'from'          => 'user1',
2055                         'to'            => 'user2',
2056                         'state'         => 'unread',
2057                         'subject'       => 'S7',
2058                         'timemodifier'  => 7,
2059                     ),
2060                     array(
2061                         'from'          => 'user1',
2062                         'to'            => 'user2',
2063                         'state'         => 'unread',
2064                         'subject'       => 'S8',
2065                         'timemodifier'  => 8,
2066                     ),
2067                 ),
2068                 'expectations' => array(
2069                     // The most recent message between user1 and user2 was S2, even though later IDs have not been read.
2070                     'user1' => array(
2071                         array(
2072                             'messageposition'   => 0,
2073                             'with'              => 'user2',
2074                             'subject'           => '<p>S8</p>',
2075                             'unreadcount'       => 1,
2076                         ),
2077                     ),
2078                     'user2' => array(
2079                         array(
2080                             'messageposition'   => 0,
2081                             'with'              => 'user1',
2082                             'subject'           => '<p>S8</p>',
2083                             'unreadcount'       => 3,
2084                         ),
2085                     ),
2086                 ),
2087             ),
2088         );
2089     }
2091     /**
2092      * Test that creation can't create the same conversation twice for 1:1 conversations.
2093      */
2094     public function test_create_conversation_duplicate_conversations() {
2095         global $DB;
2096         $user1 = $this::getDataGenerator()->create_user();
2098         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_SELF, [$user1->id]);
2099         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_SELF, [$user1->id]);
2101         $convhash = \core_message\helper::get_conversation_hash([$user1->id]);
2102         $countconversations = $DB->count_records('message_conversations', ['convhash' => $convhash]);
2103         $this->assertEquals(1, $countconversations);
2104         $this->assertNotEmpty($conversation = \core_message\api::get_self_conversation($user1->id));
2105     }
2107     /**
2108      * Test get_conversations with a mixture of messages.
2109      *
2110      * @dataProvider get_conversations_mixed_provider
2111      * @param array $usersdata The list of users to create for this test.
2112      * @param array $messagesdata The list of messages to create.
2113      * @param array $expectations The list of expected outcomes.
2114      */
2115     public function test_get_conversations_mixed($usersdata, $contacts, $messagesdata, $expectations) {
2116         global $DB;
2118         // Create all of the users.
2119         $users = array();
2120         foreach ($usersdata as $username) {
2121             $users[$username] = $this->getDataGenerator()->create_user(array('username' => $username));
2122         }
2124         foreach ($contacts as $username => $contact) {
2125             foreach ($contact as $contactname => $blocked) {
2126                 $record = new stdClass();
2127                 $record->userid     = $users[$username]->id;
2128                 $record->contactid  = $users[$contactname]->id;
2129                 $record->blocked    = $blocked;
2130                 $record->id = $DB->insert_record('message_contacts', $record);
2131             }
2132         }
2134         $defaulttimecreated = time();
2135         foreach ($messagesdata as $messagedata) {
2136             $from       = $users[$messagedata['from']];
2137             $to         = $users[$messagedata['to']];
2138             $subject    = $messagedata['subject'];
2140             if (isset($messagedata['state']) && $messagedata['state'] == 'unread') {
2141                 $messageid = $this->send_fake_message($from, $to, $subject);
2142             } else {
2143                 // If there is no state, or the state is not 'unread', assume the message is read.
2144                 $messageid = message_post_message($from, $to, $subject, FORMAT_PLAIN);
2145             }
2147             $updatemessage = new stdClass();
2148             $updatemessage->id = $messageid;
2149             if (isset($messagedata['timecreated'])) {
2150                 $updatemessage->timecreated = $messagedata['timecreated'];
2151             } else if (isset($messagedata['timemodifier'])) {
2152                 $updatemessage->timecreated = $defaulttimecreated + $messagedata['timemodifier'];
2153             } else {
2154                 $updatemessage->timecreated = $defaulttimecreated;
2155             }
2157             $DB->update_record('messages', $updatemessage);
2158         }
2160         foreach ($expectations as $username => $data) {
2161             // Get the recent conversations for the specified user.
2162             $user = $users[$username];
2163             $conversations = array_values(\core_message\api::get_conversations($user->id));
2164             foreach ($data as $expectation) {
2165                 $otheruser = $users[$expectation['with']];
2166                 $conversation = $conversations[$expectation['messageposition']];
2167                 $this->assertEquals($otheruser->id, $conversation->members[$otheruser->id]->id);
2168                 $this->assertEquals($expectation['subject'], $conversation->messages[0]->text);
2169                 $this->assertEquals($expectation['unreadcount'], $conversation->unreadcount);
2170             }
2171         }
2172     }
2174     /**
2175      * Tests retrieving user contacts.
2176      */
2177     public function test_get_user_contacts() {
2178         // Create some users.
2179         $user1 = self::getDataGenerator()->create_user();
2181         // Set as the user.
2182         $this->setUser($user1);
2184         $user2 = new stdClass();
2185         $user2->firstname = 'User';
2186         $user2->lastname = 'A';
2187         $user2 = self::getDataGenerator()->create_user($user2);
2189         $user3 = new stdClass();
2190         $user3->firstname = 'User';
2191         $user3->lastname = 'B';
2192         $user3 = self::getDataGenerator()->create_user($user3);
2194         $user4 = new stdClass();
2195         $user4->firstname = 'User';
2196         $user4->lastname = 'C';
2197         $user4 = self::getDataGenerator()->create_user($user4);
2199         $user5 = new stdClass();
2200         $user5->firstname = 'User';
2201         $user5->lastname = 'D';
2202         $user5 = self::getDataGenerator()->create_user($user5);
2204         // Add some users as contacts.
2205         \core_message\api::add_contact($user1->id, $user2->id);
2206         \core_message\api::add_contact($user1->id, $user3->id);
2207         \core_message\api::add_contact($user1->id, $user4->id);
2209         // Retrieve the contacts.
2210         $contacts = \core_message\api::get_user_contacts($user1->id);
2212         // Confirm the data is correct.
2213         $this->assertEquals(3, count($contacts));
2215         ksort($contacts);
2217         $contact1 = array_shift($contacts);
2218         $contact2 = array_shift($contacts);
2219         $contact3 = array_shift($contacts);
2221         $this->assertEquals($user2->id, $contact1->id);
2222         $this->assertEquals(fullname($user2), $contact1->fullname);
2223         $this->assertTrue($contact1->iscontact);
2225         $this->assertEquals($user3->id, $contact2->id);
2226         $this->assertEquals(fullname($user3), $contact2->fullname);
2227         $this->assertTrue($contact2->iscontact);
2229         $this->assertEquals($user4->id, $contact3->id);
2230         $this->assertEquals(fullname($user4), $contact3->fullname);
2231         $this->assertTrue($contact3->iscontact);
2232     }
2234     /**
2235      * Tests retrieving conversation messages.
2236      */
2237     public function test_get_conversation_messages() {
2238         // Create some users.
2239         $user1 = self::getDataGenerator()->create_user();
2240         $user2 = self::getDataGenerator()->create_user();
2242         // Create conversation.
2243         $conversation = \core_message\api::create_conversation(
2244             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
2245             [$user1->id, $user2->id]
2246         );
2248         // The person doing the search.
2249         $this->setUser($user1);
2251         // Send some messages back and forth.
2252         $time = 1;
2253         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time + 1);
2254         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 2);
2255         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Writing PHPUnit tests!', $time + 3);
2256         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Word.', $time + 4);
2258         // Retrieve the messages.
2259         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id);
2261         // Confirm the conversation id is correct.
2262         $this->assertEquals($conversation->id, $convmessages['id']);
2264         // Confirm the message data is correct.
2265         $messages = $convmessages['messages'];
2266         $this->assertEquals(4, count($messages));
2267         $message1 = $messages[0];
2268         $message2 = $messages[1];
2269         $message3 = $messages[2];
2270         $message4 = $messages[3];
2272         $this->assertEquals($user1->id, $message1->useridfrom);
2273         $this->assertContains('Yo!', $message1->text);
2275         $this->assertEquals($user2->id, $message2->useridfrom);
2276         $this->assertContains('Sup mang?', $message2->text);
2278         $this->assertEquals($user1->id, $message3->useridfrom);
2279         $this->assertContains('Writing PHPUnit tests!', $message3->text);
2281         $this->assertEquals($user1->id, $message4->useridfrom);
2282         $this->assertContains('Word.', $message4->text);
2284         // Confirm the members data is correct.
2285         $members = $convmessages['members'];
2286         $this->assertEquals(2, count($members));
2287     }
2289     /**
2290      * Tests retrieving group conversation messages.
2291      */
2292     public function test_get_group_conversation_messages() {
2293         // Create some users.
2294         $user1 = self::getDataGenerator()->create_user();
2295         $user2 = self::getDataGenerator()->create_user();
2296         $user3 = self::getDataGenerator()->create_user();
2297         $user4 = self::getDataGenerator()->create_user();
2299         // Create group conversation.
2300         $conversation = \core_message\api::create_conversation(
2301             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2302             [$user1->id, $user2->id, $user3->id, $user4->id]
2303         );
2305         // The person doing the search.
2306         $this->setUser($user1);
2308         // Send some messages back and forth.
2309         $time = 1;
2310         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time + 1);
2311         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 2);
2312         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Writing PHPUnit tests!', $time + 3);
2313         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Word.', $time + 4);
2314         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Yeah!', $time + 5);
2316         // Retrieve the messages.
2317         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id);
2319         // Confirm the conversation id is correct.
2320         $this->assertEquals($conversation->id, $convmessages['id']);
2322         // Confirm the message data is correct.
2323         $messages = $convmessages['messages'];
2324         $this->assertEquals(5, count($messages));
2326         $message1 = $messages[0];
2327         $message2 = $messages[1];
2328         $message3 = $messages[2];
2329         $message4 = $messages[3];
2330         $message5 = $messages[4];
2332         $this->assertEquals($user1->id, $message1->useridfrom);
2333         $this->assertContains('Yo!', $message1->text);
2335         $this->assertEquals($user2->id, $message2->useridfrom);
2336         $this->assertContains('Sup mang?', $message2->text);
2338         $this->assertEquals($user3->id, $message3->useridfrom);
2339         $this->assertContains('Writing PHPUnit tests!', $message3->text);
2341         $this->assertEquals($user1->id, $message4->useridfrom);
2342         $this->assertContains('Word.', $message4->text);
2344         $this->assertEquals($user2->id, $message5->useridfrom);
2345         $this->assertContains('Yeah!', $message5->text);
2347         // Confirm the members data is correct.
2348         $members = $convmessages['members'];
2349         $this->assertEquals(3, count($members));
2350     }
2352     /**
2353      * Test verifying the sorting param for get_conversation_messages is respected().
2354      */
2355     public function test_get_conversation_messages_sorting() {
2356         // Create some users.
2357         $user1 = self::getDataGenerator()->create_user();
2358         $user2 = self::getDataGenerator()->create_user();
2359         $user3 = self::getDataGenerator()->create_user();
2361         // Create conversations - 1 group and 1 individual.
2362         $conversation = \core_message\api::create_conversation(
2363             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
2364             [$user1->id, $user2->id]
2365         );
2366         $conversation2 = \core_message\api::create_conversation(
2367             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2368             [$user1->id, $user2->id, $user3->id]
2369         );
2371         // Send some messages back and forth.
2372         $time = 1;
2373         $m1id = testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time + 1);
2374         $m2id = testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 2);
2375         $m3id = testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Writing PHPUnit tests!', $time + 3);
2376         $m4id = testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Word.', $time + 4);
2378         $gm1id = testhelper::send_fake_message_to_conversation($user1, $conversation2->id, 'Yo!', $time + 1);
2379         $gm2id = testhelper::send_fake_message_to_conversation($user2, $conversation2->id, 'Sup mang?', $time + 2);
2380         $gm3id = testhelper::send_fake_message_to_conversation($user3, $conversation2->id, 'Writing PHPUnit tests!', $time + 3);
2381         $gm4id = testhelper::send_fake_message_to_conversation($user1, $conversation2->id, 'Word.', $time + 4);
2383         // The person doing the search.
2384         $this->setUser($user1);
2386         // Retrieve the messages using default sort ('timecreated ASC') and verify ordering.
2387         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id);
2388         $messages = $convmessages['messages'];
2389         $this->assertEquals($m1id, $messages[0]->id);
2390         $this->assertEquals($m2id, $messages[1]->id);
2391         $this->assertEquals($m3id, $messages[2]->id);
2392         $this->assertEquals($m4id, $messages[3]->id);
2394         // Retrieve the messages without specifying DESC sort ordering, and verify ordering.
2395         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0, 'timecreated DESC');
2396         $messages = $convmessages['messages'];
2397         $this->assertEquals($m1id, $messages[3]->id);
2398         $this->assertEquals($m2id, $messages[2]->id);
2399         $this->assertEquals($m3id, $messages[1]->id);
2400         $this->assertEquals($m4id, $messages[0]->id);
2402         // Retrieve the messages using default sort ('timecreated ASC') and verify ordering.
2403         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation2->id);
2404         $messages = $convmessages['messages'];
2405         $this->assertEquals($gm1id, $messages[0]->id);
2406         $this->assertEquals($gm2id, $messages[1]->id);
2407         $this->assertEquals($gm3id, $messages[2]->id);
2408         $this->assertEquals($gm4id, $messages[3]->id);
2410         // Retrieve the messages without specifying DESC sort ordering, and verify ordering.
2411         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation2->id, 0, 0, 'timecreated DESC');
2412         $messages = $convmessages['messages'];
2413         $this->assertEquals($gm1id, $messages[3]->id);
2414         $this->assertEquals($gm2id, $messages[2]->id);
2415         $this->assertEquals($gm3id, $messages[1]->id);
2416         $this->assertEquals($gm4id, $messages[0]->id);
2417     }
2419     /**
2420      * Test retrieving conversation messages by providing a minimum timecreated value.
2421      */
2422     public function test_get_conversation_messages_time_from_only() {
2423         // Create some users.
2424         $user1 = self::getDataGenerator()->create_user();
2425         $user2 = self::getDataGenerator()->create_user();
2426         $user3 = self::getDataGenerator()->create_user();
2427         $user4 = self::getDataGenerator()->create_user();
2429         // Create group conversation.
2430         $conversation = \core_message\api::create_conversation(
2431             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2432             [$user1->id, $user2->id, $user3->id, $user4->id]
2433         );
2435         // The person doing the search.
2436         $this->setUser($user1);
2438         // Send some messages back and forth.
2439         $time = 1;
2440         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2441         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2442         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2443         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2445         // Retrieve the messages from $time, which should be all of them.
2446         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0, 'timecreated ASC', $time);
2448         // Confirm the conversation id is correct.
2449         $this->assertEquals($conversation->id, $convmessages['id']);
2451         // Confirm the message data is correct.
2452         $messages = $convmessages['messages'];
2453         $this->assertEquals(4, count($messages));
2455         $message1 = $messages[0];
2456         $message2 = $messages[1];
2457         $message3 = $messages[2];
2458         $message4 = $messages[3];
2460         $this->assertContains('Message 1', $message1->text);
2461         $this->assertContains('Message 2', $message2->text);
2462         $this->assertContains('Message 3', $message3->text);
2463         $this->assertContains('Message 4', $message4->text);
2465         // Confirm the members data is correct.
2466         $members = $convmessages['members'];
2467         $this->assertEquals(3, count($members));
2469         // Retrieve the messages from $time + 3, which should only be the 2 last messages.
2470         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0,
2471             'timecreated ASC', $time + 3);
2473         // Confirm the conversation id is correct.
2474         $this->assertEquals($conversation->id, $convmessages['id']);
2476         // Confirm the message data is correct.
2477         $messages = $convmessages['messages'];
2478         $this->assertEquals(2, count($messages));
2480         $message1 = $messages[0];
2481         $message2 = $messages[1];
2483         $this->assertContains('Message 3', $message1->text);
2484         $this->assertContains('Message 4', $message2->text);
2486         // Confirm the members data is correct.
2487         $members = $convmessages['members'];
2488         $this->assertEquals(2, count($members));
2489     }
2491     /**
2492      * Test retrieving conversation messages by providing a maximum timecreated value.
2493      */
2494     public function test_get_conversation_messages_time_to_only() {
2495         // Create some users.
2496         $user1 = self::getDataGenerator()->create_user();
2497         $user2 = self::getDataGenerator()->create_user();
2498         $user3 = self::getDataGenerator()->create_user();
2499         $user4 = self::getDataGenerator()->create_user();
2501         // Create group conversation.
2502         $conversation = \core_message\api::create_conversation(
2503             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2504             [$user1->id, $user2->id, $user3->id, $user4->id]
2505         );
2507         // The person doing the search.
2508         $this->setUser($user1);
2510         // Send some messages back and forth.
2511         $time = 1;
2512         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2513         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2514         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2515         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2517         // Retrieve the messages up until $time + 4, which should be all of them.
2518         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0, 'timecreated ASC',
2519             0, $time + 4);
2521         // Confirm the conversation id is correct.
2522         $this->assertEquals($conversation->id, $convmessages['id']);
2524         // Confirm the message data is correct.
2525         $messages = $convmessages['messages'];
2526         $this->assertEquals(4, count($messages));
2528         $message1 = $messages[0];
2529         $message2 = $messages[1];
2530         $message3 = $messages[2];
2531         $message4 = $messages[3];
2533         $this->assertContains('Message 1', $message1->text);
2534         $this->assertContains('Message 2', $message2->text);
2535         $this->assertContains('Message 3', $message3->text);
2536         $this->assertContains('Message 4', $message4->text);
2538         // Confirm the members data is correct.
2539         $members = $convmessages['members'];
2540         $this->assertEquals(3, count($members));
2542         // Retrieve the messages up until $time + 2, which should be the first two.
2543         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0, 'timecreated ASC',
2544             0, $time + 2);
2546         // Confirm the conversation id is correct.
2547         $this->assertEquals($conversation->id, $convmessages['id']);
2549         // Confirm the message data is correct.
2550         $messages = $convmessages['messages'];
2551         $this->assertEquals(2, count($messages));
2553         $message1 = $messages[0];
2554         $message2 = $messages[1];
2556         $this->assertContains('Message 1', $message1->text);
2557         $this->assertContains('Message 2', $message2->text);
2559         // Confirm the members data is correct.
2560         $members = $convmessages['members'];
2561         $this->assertEquals(2, count($members));
2562     }
2564     /**
2565      * Test retrieving conversation messages by providing a minimum and maximum timecreated value.
2566      */
2567     public function test_get_conversation_messages_time_from_and_to() {
2568         // Create some users.
2569         $user1 = self::getDataGenerator()->create_user();
2570         $user2 = self::getDataGenerator()->create_user();
2571         $user3 = self::getDataGenerator()->create_user();
2572         $user4 = self::getDataGenerator()->create_user();
2574         // Create group conversation.
2575         $conversation = \core_message\api::create_conversation(
2576             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2577             [$user1->id, $user2->id, $user3->id, $user4->id]
2578         );
2580         // The person doing the search.
2581         $this->setUser($user1);
2583         // Send some messages back and forth.
2584         $time = 1;
2585         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2586         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2587         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2588         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2590         // Retrieve the messages from $time + 2 up until $time + 3, which should be 2nd and 3rd message.
2591         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0,
2592             'timecreated ASC', $time + 2, $time + 3);
2594         // Confirm the conversation id is correct.
2595         $this->assertEquals($conversation->id, $convmessages['id']);
2597         // Confirm the message data is correct.
2598         $messages = $convmessages['messages'];
2599         $this->assertEquals(2, count($messages));
2601         $message1 = $messages[0];
2602         $message2 = $messages[1];
2604         $this->assertContains('Message 2', $message1->text);
2605         $this->assertContains('Message 3', $message2->text);
2607         // Confirm the members data is correct.
2608         $members = $convmessages['members'];
2609         $this->assertEquals(2, count($members));
2610     }
2613     /**
2614      * Test retrieving conversation messages by providing a limitfrom value.
2615      */
2616     public function test_get_conversation_messages_limitfrom_only() {
2617         // Create some users.
2618         $user1 = self::getDataGenerator()->create_user();
2619         $user2 = self::getDataGenerator()->create_user();
2620         $user3 = self::getDataGenerator()->create_user();
2621         $user4 = self::getDataGenerator()->create_user();
2623         // Create group conversation.
2624         $conversation = \core_message\api::create_conversation(
2625             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2626             [$user1->id, $user2->id, $user3->id, $user4->id]
2627         );
2629         // The person doing the search.
2630         $this->setUser($user1);
2632         // Send some messages back and forth.
2633         $time = 1;
2634         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2635         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2636         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2637         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2639         // Retrieve the messages from $time, which should be all of them.
2640         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 2);
2642         // Confirm the conversation id is correct.
2643         $messages = $convmessages['messages'];
2644         $this->assertEquals($conversation->id, $convmessages['id']);
2646         // Confirm the message data is correct.
2647         $this->assertEquals(2, count($messages));
2649         $message1 = $messages[0];
2650         $message2 = $messages[1];
2652         $this->assertContains('Message 3', $message1->text);
2653         $this->assertContains('Message 4', $message2->text);
2655         // Confirm the members data is correct.
2656         $members = $convmessages['members'];
2657         $this->assertEquals(2, count($members));
2658     }
2660     /**
2661      * Test retrieving conversation messages by providing a limitnum value.
2662      */
2663     public function test_get_conversation_messages_limitnum() {
2664         // Create some users.
2665         $user1 = self::getDataGenerator()->create_user();
2666         $user2 = self::getDataGenerator()->create_user();
2667         $user3 = self::getDataGenerator()->create_user();
2668         $user4 = self::getDataGenerator()->create_user();
2670         // Create group conversation.
2671         $conversation = \core_message\api::create_conversation(
2672             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2673             [$user1->id, $user2->id, $user3->id, $user4->id]
2674         );
2676         // The person doing the search.
2677         $this->setUser($user1);
2679         // Send some messages back and forth.
2680         $time = 1;
2681         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2682         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2683         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2684         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2686         // Retrieve the messages from $time, which should be all of them.
2687         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 2, 1);
2689         // Confirm the conversation id is correct.
2690         $messages = $convmessages['messages'];
2691         $this->assertEquals($conversation->id, $convmessages['id']);
2693         // Confirm the message data is correct.
2694         $messages = $convmessages['messages'];
2695         $this->assertEquals(1, count($messages));
2697         $message1 = $messages[0];
2699         $this->assertContains('Message 3', $message1->text);
2701         // Confirm the members data is correct.
2702         $members = $convmessages['members'];
2703         $this->assertEquals(1, count($members));
2704     }
2706     /**
2707      * Tests retrieving most recent conversation message.
2708      */
2709     public function test_get_most_recent_conversation_message() {
2710         // Create some users.
2711         $user1 = self::getDataGenerator()->create_user();
2712         $user2 = self::getDataGenerator()->create_user();
2713         $user3 = self::getDataGenerator()->create_user();
2715         // Create group conversation.
2716         $conversation = \core_message\api::create_conversation(
2717             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2718             [$user1->id, $user2->id, $user3->id]
2719         );
2721         // The person getting the most recent conversation message.
2722         $this->setUser($user1);
2724         // Send some messages back and forth.
2725         $time = 1;
2726         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time + 1);
2727         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 2);
2728         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Writing PHPUnit tests!', $time + 3);
2729         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Word.', $time + 4);
2731         // Retrieve the most recent messages.
2732         $message = \core_message\api::get_most_recent_conversation_message($conversation->id, $user1->id);
2734         // Check the results are correct.
2735         $this->assertEquals($user2->id, $message->useridfrom);
2736         $this->assertContains('Word.', $message->text);
2737     }
2739     /**
2740      * Tests checking if a user can mark all messages as read.
2741      */
2742     public function test_can_mark_all_messages_as_read() {
2743         // Set as the admin.
2744         $this->setAdminUser();
2746         // Create some users.
2747         $user1 = self::getDataGenerator()->create_user();
2748         $user2 = self::getDataGenerator()->create_user();
2749         $user3 = self::getDataGenerator()->create_user();
2751         // Send some messages back and forth.
2752         $time = 1;
2753         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
2754         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
2755         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
2756         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
2758         $conversationid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
2760         // The admin can do anything.
2761         $this->assertTrue(\core_message\api::can_mark_all_messages_as_read($user1->id, $conversationid));
2763         // Set as the user 1.
2764         $this->setUser($user1);
2766         // The user can mark the messages as he is in the conversation.
2767         $this->assertTrue(\core_message\api::can_mark_all_messages_as_read($user1->id, $conversationid));
2769         // User 1 can not mark the messages read for user 2.
2770         $this->assertFalse(\core_message\api::can_mark_all_messages_as_read($user2->id, $conversationid));
2772         // This user is not a part of the conversation.
2773         $this->assertFalse(\core_message\api::can_mark_all_messages_as_read($user3->id, $conversationid));
2774     }
2776     /**
2777      * Tests checking if a user can delete a conversation.
2778      */
2779     public function test_can_delete_conversation() {
2780         // Set as the admin.
2781         $this->setAdminUser();
2783         // Create some users.
2784         $user1 = self::getDataGenerator()->create_user();
2785         $user2 = self::getDataGenerator()->create_user();
2787         // Send some messages back and forth.
2788         $time = 1;
2789         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
2790         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
2791         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
2792         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
2794         $conversationid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
2796         // The admin can do anything.
2797         $this->assertTrue(\core_message\api::can_delete_conversation($user1->id, $conversationid));
2799         // Set as the user 1.
2800         $this->setUser($user1);
2802         // They can delete their own messages.
2803         $this->assertTrue(\core_message\api::can_delete_conversation($user1->id, $conversationid));
2805         // They can't delete someone elses.
2806         $this->assertFalse(\core_message\api::can_delete_conversation($user2->id, $conversationid));
2807     }
2809     /**
2810      * Tests deleting a conversation by conversation id.
2811      */
2812     public function test_delete_conversation_by_id() {
2813         global $DB;
2815         // Create some users.
2816         $user1 = self::getDataGenerator()->create_user();
2817         $user2 = self::getDataGenerator()->create_user();
2819         // The person doing the search.
2820         $this->setUser($user1);
2822         // Get self-conversation.
2823         $sc1 = \core_message\api::get_self_conversation($user1->id);
2824         $sc2 = \core_message\api::get_self_conversation($user2->id);
2826         // Send some messages back and forth.
2827         $time = 1;
2828         $m1id = $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
2829         $m2id = $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
2830         $m3id = $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
2831         $m4id = $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
2832         $m5id = testhelper::send_fake_message_to_conversation($user1, $sc1->id, 'Hi to myself!', $time + 5);
2833         $m6id = testhelper::send_fake_message_to_conversation($user2, $sc2->id, 'I am talking with myself', $time + 6);
2835         $conversationid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
2837         // Delete the individual conversation between user1 and user2 (only for user1).
2838         \core_message\api::delete_conversation_by_id($user1->id, $conversationid);
2840         $muas = $DB->get_records('message_user_actions', array(), 'timecreated ASC');
2841         $this->assertCount(4, $muas);
2842         // Sort by id.
2843         ksort($muas);
2845         $mua1 = array_shift($muas);
2846         $mua2 = array_shift($muas);
2847         $mua3 = array_shift($muas);
2848         $mua4 = array_shift($muas);
2850         $this->assertEquals($user1->id, $mua1->userid);
2851         $this->assertEquals($m1id, $mua1->messageid);
2852         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua1->action);
2854         $this->assertEquals($user1->id, $mua2->userid);
2855         $this->assertEquals($m2id, $mua2->messageid);
2856         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua2->action);
2858         $this->assertEquals($user1->id, $mua3->userid);
2859         $this->assertEquals($m3id, $mua3->messageid);
2860         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua3->action);
2862         $this->assertEquals($user1->id, $mua4->userid);
2863         $this->assertEquals($m4id, $mua4->messageid);
2864         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua4->action);
2866         // Delete the self-conversation as user 1.
2867         \core_message\api::delete_conversation_by_id($user1->id, $sc1->id);
2869         $muas = $DB->get_records('message_user_actions', array(), 'timecreated ASC');
2870         $this->assertCount(5, $muas);
2872         // Sort by id.
2873         ksort($muas);
2875         $mua1 = array_shift($muas);
2876         $mua2 = array_shift($muas);
2877         $mua3 = array_shift($muas);
2878         $mua4 = array_shift($muas);
2879         $mua5 = array_shift($muas);
2881         // Check only messages in self-conversion for user1 are deleted (self-conversation for user2 shouldn't be removed).
2882         $this->assertEquals($user1->id, $mua5->userid);
2883         $this->assertEquals($m5id, $mua5->messageid);
2884         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua5->action);
2885     }
2887     /**
2888      * Tests counting unread conversations.
2889      */
2890     public function test_count_unread_conversations() {
2891         $this->resetAfterTest(true);
2893         // Create some users.
2894         $user1 = self::getDataGenerator()->create_user();
2895         $user2 = self::getDataGenerator()->create_user();
2896         $user3 = self::getDataGenerator()->create_user();
2897         $user4 = self::getDataGenerator()->create_user();
2899         // The person wanting the conversation count.
2900         $this->setUser($user1);
2902         // Send some messages back and forth, have some different conversations with different users.
2903         $this->send_fake_message($user1, $user2, 'Yo!');
2904         $this->send_fake_message($user2, $user1, 'Sup mang?');
2905         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!');
2906         $this->send_fake_message($user2, $user1, 'Word.');
2908         $this->send_fake_message($user1, $user3, 'Booyah');
2909         $this->send_fake_message($user3, $user1, 'Whaaat?');
2910         $this->send_fake_message($user1, $user3, 'Nothing.');
2911         $this->send_fake_message($user3, $user1, 'Cool.');
2913         $this->send_fake_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?');
2914         $this->send_fake_message($user4, $user1, 'Yah brah, it\'s pretty rad.');
2915         $this->send_fake_message($user1, $user4, 'Dope.');
2917         // Check the amount for the current user.
2918         $this->assertEquals(3, core_message\api::count_unread_conversations());
2920         // Check the amount for the second user.
2921         $this->assertEquals(1, core_message\api::count_unread_conversations($user2));
2922     }
2924     /**
2925      * Tests counting unread conversations where one conversation is disabled.
2926      */
2927     public function test_count_unread_conversations_disabled() {
2928         $this->resetAfterTest(true);
2930         // Create some users.
2931         $user1 = self::getDataGenerator()->create_user();
2932         $user2 = self::getDataGenerator()->create_user();
2933         $user3 = self::getDataGenerator()->create_user();
2934         $user4 = self::getDataGenerator()->create_user();
2936         // The person wanting the conversation count.
2937         $this->setUser($user1);
2939         // Send some messages back and forth, have some different conversations with different users.
2940         $this->send_fake_message($user1, $user2, 'Yo!');
2941         $this->send_fake_message($user2, $user1, 'Sup mang?');
2942         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!');
2943         $this->send_fake_message($user2, $user1, 'Word.');
2945         $this->send_fake_message($user1, $user3, 'Booyah');
2946         $this->send_fake_message($user3, $user1, 'Whaaat?');
2947         $this->send_fake_message($user1, $user3, 'Nothing.');
2948         $this->send_fake_message($user3, $user1, 'Cool.');
2950         $this->send_fake_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?');
2951         $this->send_fake_message($user4, $user1, 'Yah brah, it\'s pretty rad.');
2952         $this->send_fake_message($user1, $user4, 'Dope.');
2954         // Let's disable the last conversation.
2955         $conversationid = core_message\api::get_conversation_between_users([$user1->id, $user4->id]);
2956         core_message\api::disable_conversation($conversationid);
2958         // Check that the disabled conversation was not included.
2959         $this->assertEquals(2, core_message\api::count_unread_conversations());
2960     }
2962     /**
2963      * Tests deleting a conversation.
2964      */
2965     public function test_get_all_message_preferences() {
2966         $user = self::getDataGenerator()->create_user();
2967         $this->setUser($user);
2969         // Set a couple of preferences to test.
2970         set_user_preference('message_provider_mod_assign_assign_notification_loggedin', 'popup', $user);
2971         set_user_preference('message_provider_mod_assign_assign_notification_loggedoff', 'email', $user);
2973         $processors = get_message_processors();
2974         $providers = message_get_providers_for_user($user->id);
2975         $prefs = \core_message\api::get_all_message_preferences($processors, $providers, $user);
2977         $this->assertEquals(1, $prefs->mod_assign_assign_notification_loggedin['popup']);
2978         $this->assertEquals(1, $prefs->mod_assign_assign_notification_loggedoff['email']);
2979     }
2981     /**
2982      * Tests the user can send a message.
2983      */
2984     public function test_can_send_message() {
2985         // Create some users.
2986         $user1 = self::getDataGenerator()->create_user();
2987         $user2 = self::getDataGenerator()->create_user();
2989         // Set as the first user.
2990         $this->setUser($user1);
2992         // With the default privacy setting, users can't message them.
2993         $this->assertFalse(\core_message\api::can_send_message($user2->id, $user1->id));
2995         // Enrol users to the same course.
2996         $course = $this->getDataGenerator()->create_course();
2997         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
2998         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
2999         // After enrolling users to the course, they should be able to message them with the default privacy setting.
3000         $this->assertTrue(\core_message\api::can_send_message($user2->id, $user1->id));
3001     }
3003     /**
3004      * Tests the user can't send a message without proper capability.
3005      */
3006     public function test_can_send_message_without_sendmessage_cap() {
3007         global $DB;
3009         // Create some users.
3010         $user1 = self::getDataGenerator()->create_user();
3011         $user2 = self::getDataGenerator()->create_user();
3013         // Set as the user 1.
3014         $this->setUser($user1);
3016         // Remove the capability to send a message.
3017         $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
3018         unassign_capability('moodle/site:sendmessage', $roleids['user'],
3019             context_system::instance());
3021         // Check that we can not post a message without the capability.
3022         $this->assertFalse(\core_message\api::can_send_message($user2->id, $user1->id));
3023     }
3025     /**
3026      * Tests the user can send a message when they are contact.
3027      */
3028     public function test_can_send_message_when_contact() {
3029         // Create some users.
3030         $user1 = self::getDataGenerator()->create_user();
3031         $user2 = self::getDataGenerator()->create_user();
3033         // Set as the first user.
3034         $this->setUser($user1);
3036         // Check that we can not send user2 a message.
3037         $this->assertFalse(\core_message\api::can_send_message($user2->id, $user1->id));
3039         // Add users as contacts.
3040         \core_message\api::add_contact($user1->id, $user2->id);
3042         // Check that the return result is now true.
3043         $this->assertTrue(\core_message\api::can_send_message($user2->id, $user1->id));
3044     }
3046     /**
3047      * Tests the user can't send a message if they are not a contact and the user
3048      * has requested messages only from contacts.
3049      */
3050     public function test_can_send_message_when_not_contact() {
3051         // Create some users.
3052         $user1 = self::getDataGenerator()->create_user();
3053         $user2 = self::getDataGenerator()->create_user();
3055         // Set as the first user.
3056         $this->setUser($user1);
3058         // Set the second user's preference to not receive messages from non-contacts.
3059         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2->id);
3061         // Check that we can not send user 2 a message.
3062         $this->assertFalse(\core_message\api::can_send_message($user2->id, $user1->id));
3063     }
3065     /**
3066      * Tests the user can't send a message if they are blocked.
3067      */
3068     public function test_can_send_message_when_blocked() {
3069         // Create some users.
3070         $user1 = self::getDataGenerator()->create_user();
3071         $user2 = self::getDataGenerator()->create_user();
3073         // Set the user.
3074         $this->setUser($user1);
3076         // Block the second user.
3077         \core_message\api::block_user($user1->id, $user2->id);
3079         // Check that the second user can no longer send the first user a message.
3080         $this->assertFalse(\core_message\api::can_send_message($user1->id, $user2->id));
3081     }
3083     /**
3084      * Tests the user can send a message when site-wide messaging setting is enabled,
3085      * even if they are not a contact and are not members of the same course.
3086      */
3087     public function test_can_send_message_site_messaging_setting() {
3088         // Create some users.
3089         $user1 = self::getDataGenerator()->create_user();
3090         $user2 = self::getDataGenerator()->create_user();
3092         // Set as the first user.
3093         $this->setUser($user1);
3095         // By default, user only can be messaged by contacts and members of any of his/her courses.
3096         $this->assertFalse(\core_message\api::can_send_message($user2->id, $user1->id));
3098         // Enable site-wide messagging privacy setting. The user will be able to receive messages from everybody.
3099         set_config('messagingallusers', true);
3101         // Set the second user's preference to receive messages from everybody.
3102         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_SITE, $user2->id);
3104         // Check that we can send user2 a message.
3105         $this->assertTrue(\core_message\api::can_send_message($user2->id, $user1->id));
3107         // Disable site-wide messagging privacy setting. The user will be able to receive messages from contacts
3108         // and members sharing a course with her.
3109         set_config('messagingallusers', false);
3111         // As site-wide messaging setting is disabled, the value for user2 will be changed to MESSAGE_PRIVACY_COURSEMEMBER.
3112         $this->assertFalse(\core_message\api::can_send_message($user2->id, $user1->id));
3114         // Enrol users to the same course.
3115         $course = $this->getDataGenerator()->create_course();
3116         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3117         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3118         // Check that we can send user2 a message because they are sharing a course.
3119         $this->assertTrue(\core_message\api::can_send_message($user2->id, $user1->id));
3121         // Set the second user's preference to receive messages only from contacts.
3122         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2->id);
3123         // Check that now the user2 can't be contacted because user1 is not their contact.
3124         $this->assertFalse(\core_message\api::can_send_message($user2->id, $user1->id));
3126         // Make contacts user1 and user2.
3127         \core_message\api::add_contact($user2->id, $user1->id);
3128         // Check that we can send user2 a message because they are contacts.
3129         $this->assertTrue(\core_message\api::can_send_message($user2->id, $user1->id));
3130     }
3132     /**
3133      * Tests the user with the messageanyuser capability can send a message.
3134      */
3135     public function test_can_send_message_with_messageanyuser_cap() {
3136         global $DB;
3138         // Create some users.
3139         $teacher1 = self::getDataGenerator()->create_user();
3140         $student1 = self::getDataGenerator()->create_user();
3141         $student2 = self::getDataGenerator()->create_user();
3143         // Create users not enrolled in any course.
3144         $user1 = self::getDataGenerator()->create_user();
3146         // Create a course.
3147         $course1 = $this->getDataGenerator()->create_course();
3149         // Enrol the users in the course.
3150         $this->getDataGenerator()->enrol_user($teacher1->id, $course1->id, 'editingteacher');
3151         $this->getDataGenerator()->enrol_user($student1->id, $course1->id, 'student');
3152         $this->getDataGenerator()->enrol_user($student2->id, $course1->id, 'student');
3154         // Set some student preferences to not receive messages from non-contacts.
3155         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $student1->id);
3157         // Check that we can send student1 a message because teacher has the messageanyuser cap by default.
3158         $this->assertTrue(\core_message\api::can_send_message($student1->id, $teacher1->id));
3160         // Check that the teacher can't contact user1 because it's not his teacher.
3161         $this->assertFalse(\core_message\api::can_send_message($user1->id, $teacher1->id));
3163         // Remove the messageanyuser capability from the course1 for teachers.
3164         $coursecontext = context_course::instance($course1->id);
3165         $teacherrole = $DB->get_record('role', ['shortname' => 'editingteacher']);
3166         assign_capability('moodle/site:messageanyuser', CAP_PROHIBIT, $teacherrole->id, $coursecontext->id);
3167         $coursecontext->mark_dirty();
3169         // Check that we can't send user1 a message because they are not contacts.
3170         $this->assertFalse(\core_message\api::can_send_message($student1->id, $teacher1->id));
3172         // However, teacher can message student2 because they are sharing a course.
3173         $this->assertTrue(\core_message\api::can_send_message($student2->id, $teacher1->id));
3174     }
3176     /**
3177      * Tests the user when blocked will not be able to send messages if they are blocked.
3178      */
3179     public function test_can_send_message_even_if_blocked() {
3180         $this->resetAfterTest();
3182         $user1 = self::getDataGenerator()->create_user();
3183         $user2 = self::getDataGenerator()->create_user();
3185         $this->assertFalse(\core_message\api::can_send_message($user2->id, $user1->id, true));
3186     }
3188     /**
3189      * Tests the user will be able to send a message even if they are blocked as the user
3190      * has the capability 'moodle/site:messageanyuser'.
3191      */
3192     public function test_can_send_message_even_if_blocked_with_message_any_user_cap() {
3193         global $DB;
3195         $this->resetAfterTest();
3197         $user1 = self::getDataGenerator()->create_user();
3198         $user2 = self::getDataGenerator()->create_user();
3200         $authenticateduserrole = $DB->get_record('role', array('shortname' => 'user'));
3201         assign_capability('moodle/site:messageanyuser', CAP_ALLOW, $authenticateduserrole->id, context_system::instance(), true);
3203         $this->assertTrue(\core_message\api::can_send_message($user2->id, $user1->id, true));
3204     }
3206     /**
3207      * Tests the user will be able to send a message even if they are blocked as the user
3208      * has the capability 'moodle/site:readallmessages'.
3209      */
3210     public function test_can_send_message_even_if_blocked_with_read_all_message_cap() {
3211         global $DB;
3213         $this->resetAfterTest();
3215         $user1 = self::getDataGenerator()->create_user();
3216         $user2 = self::getDataGenerator()->create_user();
3218         $authenticateduserrole = $DB->get_record('role', array('shortname' => 'user'));
3219         assign_capability('moodle/site:readallmessages', CAP_ALLOW, $authenticateduserrole->id, context_system::instance(), true);
3221         $this->assertTrue(\core_message\api::can_send_message($user2->id, $user1->id, true));
3222     }
3224     /**
3225      * Tests the user can not always send a message if they are blocked just because they share a course.
3226      */
3227     public function test_can_send_message_even_if_blocked_shared_course() {
3228         $this->resetAfterTest();
3230         // Create some users.
3231         $user1 = self::getDataGenerator()->create_user();
3232         $user2 = self::getDataGenerator()->create_user();
3234         $course = self::getDataGenerator()->create_course();
3236         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3237         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3239         $this->assertFalse(\core_message\api::can_send_message($user2->id, $user1->id, true));
3240     }
3242     /**
3243      * Tests the user can always send a message even if they are blocked because they share a course and
3244      * have the capability 'moodle/site:messageanyuser' at the course context.
3245      */
3246     public function test_can_send_message_even_if_blocked_shared_course_with_message_any_user_cap() {
3247         global $DB;
3249         $this->resetAfterTest();
3251         $editingteacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
3253         $teacher = self::getDataGenerator()->create_user();
3254         $student = self::getDataGenerator()->create_user();
3256         $course = self::getDataGenerator()->create_course();
3258         $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $editingteacherrole->id);
3259         $this->getDataGenerator()->enrol_user($student->id, $course->id);
3261         assign_capability('moodle/site:messageanyuser', CAP_ALLOW, $editingteacherrole->id,
3262             context_course::instance($course->id), true);
3264         // Check that the second user can no longer send the first user a message.
3265         $this->assertTrue(\core_message\api::can_send_message($student->id, $teacher->id, true));
3266     }
3268     /**
3269      * Test that calling to can_post_message() now shows debugging. MDL-65093.
3270      *
3271      * @deprecated since 3.8
3272      * @todo Final deprecation in MDL-66266
3273      */
3274     public function test_can_post_emits_debugging() {
3275         // Create some users.
3276         $user1 = self::getDataGenerator()->create_user();
3277         $user2 = self::getDataGenerator()->create_user();
3279         // Set as the first user.
3280         $this->setUser($user1);
3282         // With the default privacy setting, users can't message them.
3283         $this->assertFalse(\core_message\api::can_post_message($user2));
3284         $this->assertDebuggingCalled('\core_message\api::can_post_message is deprecated, please use ' .
3285             '\core_message\api::can_send_message instead.', DEBUG_DEVELOPER);
3286     }
3288     /**
3289      * Verify the expected behaviour of the can_send_message_to_conversation() method for authenticated users with default settings.
3290      */
3291     public function test_can_send_message_to_conversation_basic() {
3292         // Create some users.
3293         $user1 = self::getDataGenerator()->create_user();
3294         $user2 = self::getDataGenerator()->create_user();
3295         $user3 = self::getDataGenerator()->create_user();
3297         // Create an individual conversation between user1 and user2.
3298         $ic1 = \core_message\api::create_conversation(
3299             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3300             [
3301                 $user1->id,
3302                 $user2->id
3303             ]
3304         );
3306         // Create a group conversation between and users 1, 2 and 3.
3307         $gc1 = \core_message\api::create_conversation(
3308             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3309             [
3310                 $user1->id,
3311                 $user2->id,
3312                 $user3->id
3313             ]
3314         );
3316         // Get a self-conversation for user1.
3317         $sc1 = \core_message\api::get_self_conversation($user1->id);
3319         // For group conversations, there are no user privacy checks, so only membership in the conversation is needed.
3320         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3322         // For self conversations, there are no user privacy checks, so only membership in the conversation is needed.
3323         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $sc1->id));
3325         // For individual conversations, the default privacy setting of 'only contacts and course members' applies.
3326         // Users are not in the same course, nor are they contacts, so messages cannot be sent.
3327         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3329         // Enrol the users into the same course.
3330         $course = $this->getDataGenerator()->create_course();
3331         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3332         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3334         // After enrolling users to the course, they should be able to message them with the default privacy setting.
3335         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3336     }
3338     /**
3339      * Verify the behaviour of can_send_message_to_conversation() for authenticated users without the sendmessage capability.
3340      */
3341     public function test_can_send_message_to_conversation_sendmessage_cap() {
3342         global $DB;
3344         $user1 = self::getDataGenerator()->create_user();
3345         $user2 = self::getDataGenerator()->create_user();
3346         $user3 = self::getDataGenerator()->create_user();
3348         // Enrol the users into the same course.
3349         $course = $this->getDataGenerator()->create_course();
3350         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3351         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3352         $this->getDataGenerator()->enrol_user($user3->id, $course->id);
3354         // Create an individual conversation between user1 and user2.
3355         $ic1 = \core_message\api::create_conversation(
3356             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3357             [
3358                 $user1->id,
3359                 $user2->id
3360             ]
3361         );
3363         // Group conversation between and users 1, 2 and 3.
3364         $gc1 = \core_message\api::create_conversation(
3365             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3366             [
3367                 $user1->id,
3368                 $user2->id,
3369                 $user3->id
3370             ]
3371         );
3373         // Default settings - user1 can send a message to both conversations.
3374         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3375         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3377         // Remove the capability to send a message.
3378         $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
3379         unassign_capability('moodle/site:sendmessage', $roleids['user'], context_system::instance());
3381         // Verify that a user cannot send a message to either an individual or a group conversation.
3382         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3383         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3384     }
3386     /**
3387      * Verify the behaviour of can_send_message_to_conversation() for authenticated users without the messageanyuser capability.
3388      */
3389     public function test_can_send_message_to_conversation_messageanyuser_cap() {
3390         global $DB;
3392         $user1 = self::getDataGenerator()->create_user();
3393         $user2 = self::getDataGenerator()->create_user();
3394         $user3 = self::getDataGenerator()->create_user();
3396         // Enrol the users into the same course.
3397         $course = $this->getDataGenerator()->create_course();
3398         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3399         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3400         $this->getDataGenerator()->enrol_user($user3->id, $course->id);
3402         // Create an individual conversation between user1 and user2.
3403         $ic1 = \core_message\api::create_conversation(
3404             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3405             [
3406                 $user1->id,
3407                 $user2->id
3408             ]
3409         );
3411         // Group conversation between and users 1, 2 and 3.
3412         $gc1 = \core_message\api::create_conversation(
3413             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3414             [
3415                 $user1->id,
3416                 $user2->id,
3417                 $user3->id
3418             ]
3419         );
3421         // Update the message preference for user2, so they can only be messaged by contacts.
3422         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2->id);
3424         // Verify that the user cannot be contacted in the individual conversation and that groups are unaffected.
3425         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3426         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3428         // Assign the 'messageanyuser' capability to user1 at system context.
3429         $systemcontext = context_system::instance();
3430         $authenticateduser = $DB->get_record('role', ['shortname' => 'user']);
3431         assign_capability('moodle/site:messageanyuser', CAP_ALLOW, $authenticateduser->id, $systemcontext->id);
3433         // Check that user1 can now message user2 due to the capability, and that group conversations is again unaffected.
3434         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3435         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3436     }
3438     /**
3439      * Test verifying that users cannot send messages to conversations they are not a part of.
3440      */
3441     public function test_can_send_message_to_conversation_non_member() {
3442         // Create some users.
3443         $user1 = self::getDataGenerator()->create_user();
3444         $user2 = self::getDataGenerator()->create_user();
3445         $user3 = self::getDataGenerator()->create_user();
3446         $user4 = self::getDataGenerator()->create_user();
3448         // Enrol the users into the same course.
3449         $course = $this->getDataGenerator()->create_course();
3450         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3451         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3452         $this->getDataGenerator()->enrol_user($user3->id, $course->id);
3453         $this->getDataGenerator()->enrol_user($user4->id, $course->id);
3455         // Create an individual conversation between user1 and user2.
3456         $ic1 = \core_message\api::create_conversation(
3457             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3458             [
3459                 $user1->id,
3460                 $user2->id
3461             ]
3462         );
3464         // Create a group conversation between and users 1, 2 and 3.
3465         $gc1 = \core_message\api::create_conversation(
3466             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3467             [
3468                 $user1->id,
3469                 $user2->id,
3470                 $user3->id
3471             ]
3472         );
3474         // Get a self-conversation for user1.
3475         $sc1 = \core_message\api::get_self_conversation($user1->id);
3477         // Verify, non members cannot send a message.
3478         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user4->id, $gc1->id));
3479         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user4->id, $ic1->id));
3480         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user4->id, $sc1->id));
3481     }
3483     /**
3484      * Test verifying the behaviour of the can_send_message_to_conversation method when privacy is set to contacts only.
3485      */
3486     public function test_can_send_message_to_conversation_privacy_contacts_only() {
3487         // Create some users.
3488         $user1 = self::getDataGenerator()->create_user();
3489         $user2 = self::getDataGenerator()->create_user();
3490         $user3 = self::getDataGenerator()->create_user();
3492         // Create an individual conversation between user1 and user2.
3493         $ic1 = \core_message\api::create_conversation(
3494             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3495             [
3496                 $user1->id,
3497                 $user2->id
3498             ]
3499         );
3501         // Create a group conversation between and users 1, 2 and 3.
3502         $gc1 = \core_message\api::create_conversation(
3503             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3504             [
3505                 $user1->id,
3506                 $user2->id,
3507                 $user3->id
3508             ]
3509         );
3511         // Set the message privacy preference to 'contacts only' for user 2.
3512         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2->id);
3514         // Verify that user1 cannot send a message to the individual conversation, but that the group conversation is unaffected.
3515         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3516         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3518         // Now, simulate a contact request (and approval) between user1 and user2.
3519         \core_message\api::create_contact_request($user1->id, $user2->id);
3520         \core_message\api::confirm_contact_request($user1->id, $user2->id);
3522         // Verify user1 can now message user2 again via their individual conversation.
3523         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3524     }
3526     /**
3527      * Test verifying the behaviour of the can_send_message_to_conversation method when privacy is set to contacts / course members.
3528      */
3529     public function test_can_send_message_to_conversation_privacy_contacts_course() {
3530         // Create some users.
3531         $user1 = self::getDataGenerator()->create_user();
3532         $user2 = self::getDataGenerator()->create_user();
3533         $user3 = self::getDataGenerator()->create_user();
3535         // Set the message privacy preference to 'contacts + course members' for user 2.
3536         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_COURSEMEMBER, $user2->id);
3538         // Create an individual conversation between user1 and user2.
3539         $ic1 = \core_message\api::create_conversation(
3540             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3541             [
3542                 $user1->id,
3543                 $user2->id
3544             ]
3545         );
3547         // Create a group conversation between and users 1, 2 and 3.
3548         $gc1 = \core_message\api::create_conversation(
3549             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3550             [
3551                 $user1->id,
3552                 $user2->id,
3553                 $user3->id
3554             ]
3555         );
3557         // Verify that users in a group conversation can message one another (i.e. privacy controls ignored).
3558         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3560         // Verify that user1 can not message user2 unless they are either contacts, or share a course.
3561         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3563         // Enrol the users into the same course.
3564         $course = $this->getDataGenerator()->create_course();
3565         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3566         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3567         $this->getDataGenerator()->enrol_user($user3->id, $course->id);
3569         // Verify that user1 can send a message to user2, based on the shared course, without being a contact.
3570         $this->assertFalse(\core_message\api::is_contact($user1->id, $user2->id));
3571         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3572     }
3574     /**
3575      * Test verifying the behaviour of the can_send_message_to_conversation method when privacy is set to any user.
3576      */
3577     public function test_can_send_message_to_conversation_privacy_sitewide() {
3578         // Create some users.
3579         $user1 = self::getDataGenerator()->create_user();
3580         $user2 = self::getDataGenerator()->create_user();
3581         $user3 = self::getDataGenerator()->create_user();
3583         // Create an individual conversation between user1 and user2.
3584         $ic1 = \core_message\api::create_conversation(
3585             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3586             [
3587                 $user1->id,
3588                 $user2->id
3589             ]
3590         );
3592         // Create a group conversation between and users 1, 2 and 3.
3593         $gc1 = \core_message\api::create_conversation(
3594             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3595             [
3596                 $user1->id,
3597                 $user2->id,
3598                 $user3->id
3599             ]
3600         );
3602         // By default, the messaging privacy dictates that users can only be contacted by contacts, and members of their courses.
3603         // Verify also, that groups are not restricted in this way.
3604         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3605         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3607         // Enable site-wide messagging privacy setting.
3608         // This enables a privacy option for users, allowing them to choose to be contactable by anybody on the site.
3609         set_config('messagingallusers', true);
3611         // Set the second user's preference to receive messages from everybody.
3612         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_SITE, $user2->id);
3614         // Check that user1 can send user2 a message, and that the group conversation is unaffected.
3615         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3616         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3618         // Disable site-wide messagging privacy setting. The user will be able to receive messages from contacts
3619         // and members sharing a course with her.
3620         set_config('messagingallusers', false);
3622         // As site-wide messaging setting is disabled, the value for user2 will be changed to MESSAGE_PRIVACY_COURSEMEMBER.
3623         // Verify also that the group conversation is unaffected.
3624         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3625         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3626     }
3628     /**
3629      * Test verifying the behaviour of the can_send_message_to_conversation method when a user is blocked.
3630      */
3631     public function test_can_send_message_to_conversation_when_blocked() {
3632         $user1 = self::getDataGenerator()->create_user();
3633         $user2 = self::getDataGenerator()->create_user();
3634         $user3 = self::getDataGenerator()->create_user();
3636         // Create an individual conversation between user1 and user2.
3637         $ic1 = \core_message\api::create_conversation(
3638             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3639             [
3640                 $user1->id,
3641                 $user2->id
3642             ]
3643         );
3645         // Create a group conversation between and users 1, 2 and 3.
3646         $gc1 = \core_message\api::create_conversation(
3647             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3648             [
3649                 $user1->id,
3650                 $user2->id,
3651                 $user3->id
3652             ]
3653         );
3655         // Enrol the users into the same course.
3656         $course = $this->getDataGenerator()->create_course();
3657         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3658         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3659         $this->getDataGenerator()->enrol_user($user3->id, $course->id);
3661         // Block the second user.
3662         \core_message\api::block_user($user1->id, $user2->id);
3664         // Check that user2 can not send user1 a message in their individual conversation.
3665         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user2->id, $ic1->id));
3667         // Verify that group conversations are unaffected.
3668         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3669         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user2->id, $gc1->id));
3670     }
3672     /**
3673      * Tests get_user_privacy_messaging_preference method.
3674      */
3675     public function test_get_user_privacy_messaging_preference() {
3676         // Create some users.
3677         $user1 = self::getDataGenerator()->create_user();
3678         $user2 = self::getDataGenerator()->create_user();
3679         $user3 = self::getDataGenerator()->create_user();
3681         // Enable site-wide messagging privacy setting. The user will be able to receive messages from everybody.
3682         set_config('messagingallusers', true);
3684         // Set some user preferences.
3685         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_SITE, $user1->id);
3686         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2->id);
3688         // Check the returned value for each user.
3689         $this->assertEquals(
3690             \core_message\api::MESSAGE_PRIVACY_SITE,
3691             \core_message\api::get_user_privacy_messaging_preference($user1->id)
3692         );
3693         $this->assertEquals(
3694             \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS,
3695             \core_message\api::get_user_privacy_messaging_preference($user2->id)
3696         );
3697         $this->assertEquals(
3698             \core_message\api::MESSAGE_PRIVACY_SITE,
3699             \core_message\api::get_user_privacy_messaging_preference($user3->id)
3700         );
3702         // Disable site-wide messagging privacy setting. The user will be able to receive messages from members of their course.
3703         set_config('messagingallusers', false);
3705         // Check the returned value for each user.
3706         $this->assertEquals(
3707             \core_message\api::MESSAGE_PRIVACY_COURSEMEMBER,
3708             \core_message\api::get_user_privacy_messaging_preference($user1->id)
3709         );
3710         $this->assertEquals(
3711             \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS,
3712             \core_message\api::get_user_privacy_messaging_preference($user2->id)
3713         );
3714         $this->assertEquals(
3715             \core_message\api::MESSAGE_PRIVACY_COURSEMEMBER,
3716             \core_message\api::get_user_privacy_messaging_preference($user3->id)
3717         );
3718     }
3720     /*
3721      * Tes get_message_processor api.
3722      */
3723     public function test_get_message_processor() {
3724         $processors = get_message_processors(true);
3725         if (empty($processors)) {
3726             $this->markTestSkipped("No message processors found");
3727         }
3729         $name = key($processors);
3730         $processor = current($processors);
3731         $testprocessor = \core_message\api::get_message_processor($name);
3732         $this->assertEquals($processor->name, $testprocessor->name);
3733         $this->assertEquals($processor->enabled, $testprocessor->enabled);
3734         $this->assertEquals($processor->available, $testprocessor->available);
3735         $this->assertEquals($processor->configured, $testprocessor->configured);
3737         // Disable processor and test.
3738         \core_message\api::update_processor_status($testprocessor, 0);
3739         $testprocessor = \core_message\api::get_message_processor($name, true);
3740         $this->assertEmpty($testprocessor);
3741         $testprocessor = \core_message\api::get_message_processor($name);
3742         $this->assertEquals($processor->name, $testprocessor->name);
3743         $this->assertEquals(0, $testprocessor->enabled);
3745         // Enable again and test.
3746         \core_message\api::update_processor_status($testprocessor, 1);
3747         $testprocessor = \core_message\api::get_message_processor($name, true);
3748         $this->assertEquals($processor->name, $testprocessor->name);
3749         $this->assertEquals(1, $testprocessor->enabled);
3750         $testprocessor = \core_message\api::get_message_processor($name);
3751         $this->assertEquals($processor->name, $testprocessor->name);
3752         $this->assertEquals(1, $testprocessor->enabled);
3753     }
3755     /**
3756      * Test method update_processor_status.
3757      */
3758     public function test_update_processor_status() {
3759         $processors = get_message_processors();
3760         if (empty($processors)) {
3761             $this->markTestSkipped("No message processors found");
3762         }
3763         $name = key($processors);
3764         $testprocessor = current($processors);
3766         // Enable.
3767         \core_message\api::update_processor_status($testprocessor, 1);
3768         $testprocessor = \core_message\api::get_message_processor($name);
3769         $this->assertEquals(1, $testprocessor->enabled);
3771         // Disable.
3772         \core_message\api::update_processor_status($testprocessor, 0);
3773         $testprocessor = \core_message\api::get_message_processor($name);
3774         $this->assertEquals(0, $testprocessor->enabled);
3776         // Enable again.
3777         \core_message\api::update_processor_status($testprocessor, 1);
3778         $testprocessor = \core_message\api::get_message_processor($name);
3779         $this->assertEquals(1, $testprocessor->enabled);
3780     }
3782     /**
3783      * Test method is_user_enabled.
3784      */
3785     public function is_user_enabled() {
3786         $processors = get_message_processors();
3787         if (empty($processors)) {
3788             $this->markTestSkipped("No message processors found");
3789         }
3790         $name = key($processors);
3791         $testprocessor = current($processors);
3793         // Enable.
3794         \core_message\api::update_processor_status($testprocessor, 1);
3795         $status = \core_message\api::is_processor_enabled($name);
3796         $this->assertEquals(1, $status);
3798         // Disable.
3799         \core_message\api::update_processor_status($testprocessor, 0);
3800         $status = \core_message\api::is_processor_enabled($name);
3801         $this->assertEquals(0, $status);
3803         // Enable again.
3804         \core_message\api::update_processor_status($testprocessor, 1);
3805         $status = \core_message\api::is_processor_enabled($name);
3806         $this->assertEquals(1, $status);
3807     }
3809     /**
3810      * Test returning blocked users.
3811      */
3812     public function test_get_blocked_users() {
3813         global $USER;
3815         // Set this user as the admin.
3816         $this->setAdminUser();
3818         // Create a user to add to the admin's contact list.
3819         $user1 = $this->getDataGenerator()->create_user();
3820         $user2 = $this->getDataGenerator()->create_user();
3822         // Add users to the admin's contact list.
3823         \core_message\api::block_user($USER->id, $user2->id);
3825         $this->assertCount(1, \core_message\api::get_blocked_users($USER->id));