MDL-63303 message: add count_conversations to api
[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_read_for_user($recipient->id);
56         $this->assertDebuggingCalled();
57         $this->assertEquals(message_count_unread_messages($recipient), 0);
58     }
60     public function test_mark_all_read_for_user_touser_with_fromuser() {
61         $sender1 = $this->getDataGenerator()->create_user(array('firstname' => 'Test1', 'lastname' => 'User1'));
62         $sender2 = $this->getDataGenerator()->create_user(array('firstname' => 'Test3', 'lastname' => 'User3'));
63         $recipient = $this->getDataGenerator()->create_user(array('firstname' => 'Test2', 'lastname' => 'User2'));
65         $this->send_fake_message($sender1, $recipient, 'Notification', 1);
66         $this->send_fake_message($sender1, $recipient, 'Notification', 1);
67         $this->send_fake_message($sender1, $recipient, 'Notification', 1);
68         $this->send_fake_message($sender1, $recipient);
69         $this->send_fake_message($sender1, $recipient);
70         $this->send_fake_message($sender1, $recipient);
71         $this->send_fake_message($sender2, $recipient, 'Notification', 1);
72         $this->send_fake_message($sender2, $recipient, 'Notification', 1);
73         $this->send_fake_message($sender2, $recipient, 'Notification', 1);
74         $this->send_fake_message($sender2, $recipient);
75         $this->send_fake_message($sender2, $recipient);
76         $this->send_fake_message($sender2, $recipient);
78         \core_message\api::mark_all_read_for_user($recipient->id, $sender1->id);
79         $this->assertDebuggingCalled();
80         $this->assertEquals(message_count_unread_messages($recipient), 3);
81     }
83     public function test_mark_all_read_for_user_touser_with_type() {
84         $sender = $this->getDataGenerator()->create_user(array('firstname' => 'Test1', 'lastname' => 'User1'));
85         $recipient = $this->getDataGenerator()->create_user(array('firstname' => 'Test2', 'lastname' => 'User2'));
87         $this->send_fake_message($sender, $recipient, 'Notification', 1);
88         $this->send_fake_message($sender, $recipient, 'Notification', 1);
89         $this->send_fake_message($sender, $recipient, 'Notification', 1);
90         $this->send_fake_message($sender, $recipient);
91         $this->send_fake_message($sender, $recipient);
92         $this->send_fake_message($sender, $recipient);
94         \core_message\api::mark_all_read_for_user($recipient->id, 0, MESSAGE_TYPE_NOTIFICATION);
95         $this->assertDebuggingCalled();
96         $this->assertEquals(message_count_unread_messages($recipient), 3);
98         \core_message\api::mark_all_read_for_user($recipient->id, 0, MESSAGE_TYPE_MESSAGE);
99         $this->assertDebuggingCalled();
100         $this->assertEquals(message_count_unread_messages($recipient), 0);
101     }
103     /**
104      * Test count_blocked_users.
105      */
106     public function test_count_blocked_users() {
107         global $USER;
109         // Set this user as the admin.
110         $this->setAdminUser();
112         // Create user to add to the admin's block list.
113         $user1 = $this->getDataGenerator()->create_user();
114         $user2 = $this->getDataGenerator()->create_user();
116         $this->assertEquals(0, \core_message\api::count_blocked_users());
118         // Add 1 blocked user to admin's blocked user list.
119         \core_message\api::block_user($USER->id, $user1->id);
121         $this->assertEquals(0, \core_message\api::count_blocked_users($user1));
122         $this->assertEquals(1, \core_message\api::count_blocked_users());
123     }
125     /**
126      * Tests searching users in a course.
127      */
128     public function test_search_users_in_course() {
129         // Create some users.
130         $user1 = new stdClass();
131         $user1->firstname = 'User';
132         $user1->lastname = 'One';
133         $user1 = self::getDataGenerator()->create_user($user1);
135         // The person doing the search.
136         $this->setUser($user1);
138         // Second user is going to have their last access set to now, so they are online.
139         $user2 = new stdClass();
140         $user2->firstname = 'User';
141         $user2->lastname = 'Two';
142         $user2->lastaccess = time();
143         $user2 = self::getDataGenerator()->create_user($user2);
145         // Block the second user.
146         \core_message\api::block_user($user1->id, $user2->id);
148         $user3 = new stdClass();
149         $user3->firstname = 'User';
150         $user3->lastname = 'Three';
151         $user3 = self::getDataGenerator()->create_user($user3);
153         // Create a course.
154         $course1 = new stdClass();
155         $course1->fullname = 'Course';
156         $course1->shortname = 'One';
157         $course1 = $this->getDataGenerator()->create_course($course1);
159         // Enrol the searcher and one user in the course.
160         $this->getDataGenerator()->enrol_user($user1->id, $course1->id);
161         $this->getDataGenerator()->enrol_user($user2->id, $course1->id);
163         // Perform a search.
164         $results = \core_message\api::search_users_in_course($user1->id, $course1->id, 'User');
166         $this->assertEquals(1, count($results));
168         $user = $results[0];
169         $this->assertEquals($user2->id, $user->userid);
170         $this->assertEquals(fullname($user2), $user->fullname);
171         $this->assertFalse($user->ismessaging);
172         $this->assertNull($user->lastmessage);
173         $this->assertNull($user->messageid);
174         $this->assertNull($user->isonline);
175         $this->assertFalse($user->isread);
176         $this->assertTrue($user->isblocked);
177         $this->assertNull($user->unreadcount);
178     }
180     /**
181      * Tests searching users.
182      */
183     public function test_search_users() {
184         global $DB;
186         // Create some users.
187         $user1 = new stdClass();
188         $user1->firstname = 'User';
189         $user1->lastname = 'One';
190         $user1 = self::getDataGenerator()->create_user($user1);
192         // Set as the user performing the search.
193         $this->setUser($user1);
195         $user2 = new stdClass();
196         $user2->firstname = 'User search';
197         $user2->lastname = 'Two';
198         $user2 = self::getDataGenerator()->create_user($user2);
200         $user3 = new stdClass();
201         $user3->firstname = 'User search';
202         $user3->lastname = 'Three';
203         $user3 = self::getDataGenerator()->create_user($user3);
205         $user4 = new stdClass();
206         $user4->firstname = 'User';
207         $user4->lastname = 'Four';
208         $user4 = self::getDataGenerator()->create_user($user4);
210         $user5 = new stdClass();
211         $user5->firstname = 'User search';
212         $user5->lastname = 'Five';
213         $user5 = self::getDataGenerator()->create_user($user5);
215         $user6 = new stdClass();
216         $user6->firstname = 'User';
217         $user6->lastname = 'Six';
218         $user6 = self::getDataGenerator()->create_user($user6);
220         // Create some courses.
221         $course1 = new stdClass();
222         $course1->fullname = 'Course search';
223         $course1->shortname = 'One';
224         $course1 = $this->getDataGenerator()->create_course($course1);
226         $course2 = new stdClass();
227         $course2->fullname = 'Course';
228         $course2->shortname = 'Two';
229         $course2 = $this->getDataGenerator()->create_course($course2);
231         $course3 = new stdClass();
232         $course3->fullname = 'Course';
233         $course3->shortname = 'Three search';
234         $course3 = $this->getDataGenerator()->create_course($course3);
236         $course4 = new stdClass();
237         $course4->fullname = 'Course Four';
238         $course4->shortname = 'CF100';
239         $course4 = $this->getDataGenerator()->create_course($course4);
241         $course5 = new stdClass();
242         $course5->fullname = 'Course';
243         $course5->shortname = 'Five search';
244         $course5 = $this->getDataGenerator()->create_course($course5);
246         $role = $DB->get_record('role', ['shortname' => 'student']);
247         $this->getDataGenerator()->enrol_user($user1->id, $course1->id, $role->id);
248         $this->getDataGenerator()->enrol_user($user1->id, $course2->id, $role->id);
249         $this->getDataGenerator()->enrol_user($user1->id, $course3->id, $role->id);
250         $this->getDataGenerator()->enrol_user($user1->id, $course5->id, $role->id);
252         // Add some users as contacts.
253         \core_message\api::add_contact($user1->id, $user2->id);
254         \core_message\api::add_contact($user1->id, $user3->id);
255         \core_message\api::add_contact($user1->id, $user4->id);
257         // Remove the viewparticipants capability from one of the courses.
258         $course5context = context_course::instance($course5->id);
259         assign_capability('moodle/course:viewparticipants', CAP_PROHIBIT, $role->id, $course5context->id);
261         // Perform a search $CFG->messagingallusers setting enabled.
262         set_config('messagingallusers', 1);
263         list($contacts, $courses, $noncontacts) = \core_message\api::search_users($user1->id, 'search');
265         // Check that we retrieved the correct contacts.
266         $this->assertEquals(2, count($contacts));
267         $this->assertEquals($user3->id, $contacts[0]->userid);
268         $this->assertEquals($user2->id, $contacts[1]->userid);
270         // Check that we retrieved the correct courses.
271         $this->assertEquals(2, count($courses));
272         $this->assertEquals($course3->id, $courses[0]->id);
273         $this->assertEquals($course1->id, $courses[1]->id);
275         // Check that we retrieved the correct non-contacts.
276         $this->assertEquals(1, count($noncontacts));
277         $this->assertEquals($user5->id, $noncontacts[0]->userid);
278     }
280     /**
281      * Tests searching users with empty result.
282      */
283     public function test_search_users_with_empty_result() {
285         // Create some users.
286         $user1 = new stdClass();
287         $user1->firstname = 'User';
288         $user1->lastname = 'One';
289         $user1 = self::getDataGenerator()->create_user($user1);
291         // Set as the user performing the search.
292         $this->setUser($user1);
294         $user2 = new stdClass();
295         $user2->firstname = 'User';
296         $user2->lastname = 'Two';
297         $user2 = self::getDataGenerator()->create_user($user2);
299         // Perform a search $CFG->messagingallusers setting enabled.
300         set_config('messagingallusers', 1);
301         list($contacts, $courses, $noncontacts) = \core_message\api::search_users($user1->id, 'search');
303         // Check results are empty.
304         $this->assertEquals(0, count($contacts));
305         $this->assertEquals(0, count($courses));
306         $this->assertEquals(0, count($noncontacts));
307     }
309     /**
310      * Tests searching for users when site-wide messaging is disabled.
311      *
312      * This test verifies that any contacts are returned, as well as any non-contacts whose profile we can view.
313      * If checks this by placing some users in the same course, where default caps would permit a user to view another user's
314      * profile.
315      */
316     public function test_message_search_users_messagingallusers_disabled() {
317         $this->resetAfterTest();
319         // Create some users.
320         $users = [];
321         foreach (range(1, 7) as $i) {
322             $user = new stdClass();
323             $user->firstname = ($i == 4) ? 'User' : 'User search'; // Ensure the fourth user won't match the search term.
324             $user->lastname = $i;
325             $user = $this->getDataGenerator()->create_user($user);
326             $users[$i] = $user;
327         }
329         // Enrol a few users in the same course, but leave them as non-contacts.
330         $course1 = $this->getDataGenerator()->create_course();
331         $this->setAdminUser();
332         $this->getDataGenerator()->enrol_user($users[1]->id, $course1->id);
333         $this->getDataGenerator()->enrol_user($users[6]->id, $course1->id);
334         $this->getDataGenerator()->enrol_user($users[7]->id, $course1->id);
336         // Add some other users as contacts.
337         \core_message\api::add_contact($users[1]->id, $users[2]->id);
338         \core_message\api::add_contact($users[3]->id, $users[1]->id);
339         \core_message\api::add_contact($users[1]->id, $users[4]->id);
341         // Create individual conversations between some users, one contact and one non-contact.
342         $ic1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
343             [$users[1]->id, $users[2]->id]);
344         $ic2 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
345             [$users[6]->id, $users[1]->id]);
347         // Create a group conversation between 4 users, including a contact and a non-contact.
348         $gc1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
349             [$users[1]->id, $users[2]->id, $users[4]->id, $users[7]->id], 'Project chat');
351         // Set as the user performing the search.
352         $this->setUser($users[1]);
354         // Perform a search with $CFG->messagingallusers disabled.
355         set_config('messagingallusers', 0);
356         $result = \core_message\api::message_search_users($users[1]->id, 'search');
358         // Confirm that we returns contacts and non-contacts.
359         $this->assertArrayHasKey(0, $result);
360         $this->assertArrayHasKey(1, $result);
361         $contacts = $result[0];
362         $noncontacts = $result[1];
364         // Check that we retrieved the correct contacts.
365         $this->assertCount(2, $contacts);
366         $this->assertEquals($users[2]->id, $contacts[0]->id);
367         $this->assertEquals($users[3]->id, $contacts[1]->id);
369         // Verify the correct conversations were returned for the contacts.
370         $this->assertCount(2, $contacts[0]->conversations);
371         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $contacts[0]->conversations[$gc1->id]->type);
372         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $contacts[0]->conversations[$ic1->id]->type);
374         $this->assertCount(0, $contacts[1]->conversations);
376         // Check that we retrieved the correct non-contacts.
377         // When site wide messaging is disabled, we expect to see only those users whose profiles we can view.
378         $this->assertCount(2, $noncontacts);
379         $this->assertEquals($users[6]->id, $noncontacts[0]->id);
380         $this->assertEquals($users[7]->id, $noncontacts[1]->id);
382         // Verify the correct conversations were returned for the non-contacts.
383         $this->assertCount(1, $noncontacts[0]->conversations);
384         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
385             $noncontacts[0]->conversations[$ic2->id]->type);
387         $this->assertCount(1, $noncontacts[1]->conversations);
388         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $noncontacts[1]->conversations[$gc1->id]->type);
389     }
391     /**
392      * Tests searching for users when site-wide messaging is enabled.
393      *
394      * This test verifies that any contacts are returned, as well as any non-contacts, regardless of whether the searching user
395      * can view their respective profile.
396      */
397     public function test_message_search_users_messagingallusers_enabled() {
398         $this->resetAfterTest();
400         // Create some users.
401         $users = [];
402         foreach (range(1, 8) as $i) {
403             $user = new stdClass();
404             $user->firstname = ($i == 4) ? 'User' : 'User search'; // Ensure the fourth user won't match the search term.
405             $user->lastname = $i;
406             $user = $this->getDataGenerator()->create_user($user);
407             $users[$i] = $user;
408         }
410         // Enrol a few users in the same course, but leave them as non-contacts.
411         $course1 = $this->getDataGenerator()->create_course();
412         $this->setAdminUser();
413         $this->getDataGenerator()->enrol_user($users[1]->id, $course1->id);
414         $this->getDataGenerator()->enrol_user($users[6]->id, $course1->id);
415         $this->getDataGenerator()->enrol_user($users[7]->id, $course1->id);
417         // Add some other users as contacts.
418         \core_message\api::add_contact($users[1]->id, $users[2]->id);
419         \core_message\api::add_contact($users[3]->id, $users[1]->id);
420         \core_message\api::add_contact($users[1]->id, $users[4]->id);
422         // Create individual conversations between some users, one contact and one non-contact.
423         $ic1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
424             [$users[1]->id, $users[2]->id]);
425         $ic2 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
426             [$users[6]->id, $users[1]->id]);
428         // Create a group conversation between 5 users, including a contact and a non-contact, and a user NOT in a shared course.
429         $gc1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
430             [$users[1]->id, $users[2]->id, $users[4]->id, $users[7]->id, $users[8]->id], 'Project chat');
432         // Set as the user performing the search.
433         $this->setUser($users[1]);
435         // Perform a search with $CFG->messagingallusers enabled.
436         set_config('messagingallusers', 1);
437         $result = \core_message\api::message_search_users($users[1]->id, 'search');
439         // Confirm that we returns contacts and non-contacts.
440         $this->assertArrayHasKey(0, $result);
441         $this->assertArrayHasKey(1, $result);
442         $contacts = $result[0];
443         $noncontacts = $result[1];
445         // Check that we retrieved the correct contacts.
446         $this->assertCount(2, $contacts);
447         $this->assertEquals($users[2]->id, $contacts[0]->id);
448         $this->assertEquals($users[3]->id, $contacts[1]->id);
450         // Verify the correct conversations were returned for the contacts.
451         $this->assertCount(2, $contacts[0]->conversations);
452         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $contacts[0]->conversations[$gc1->id]->type);
453         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $contacts[0]->conversations[$ic1->id]->type);
455         $this->assertCount(0, $contacts[1]->conversations);
457         // Check that we retrieved the correct non-contacts.
458         // If site wide messaging is enabled, we expect to be able to search for any users.
459         $this->assertCount(4, $noncontacts);
460         $this->assertEquals($users[5]->id, $noncontacts[0]->id);
461         $this->assertEquals($users[6]->id, $noncontacts[1]->id);
462         $this->assertEquals($users[7]->id, $noncontacts[2]->id);
463         $this->assertEquals($users[8]->id, $noncontacts[3]->id);
465         // Verify the correct conversations were returned for the non-contacts.
466         $this->assertCount(0, $noncontacts[0]->conversations);
468         $this->assertCount(1, $noncontacts[1]->conversations);
469         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
470             $noncontacts[1]->conversations[$ic2->id]->type);
472         $this->assertCount(1, $noncontacts[2]->conversations);
473         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $noncontacts[2]->conversations[$gc1->id]->type);
475         $this->assertCount(1, $noncontacts[3]->conversations);
476         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $noncontacts[3]->conversations[$gc1->id]->type);
477     }
479     /**
480      * Verify searching for users works even if no matching users from either contacts, or non-contacts can be found.
481      */
482     public function test_message_search_users_with_empty_result() {
483         $this->resetAfterTest();
485         // Create some users, but make sure neither will match the search term.
486         $user1 = new stdClass();
487         $user1->firstname = 'User';
488         $user1->lastname = 'One';
489         $user1 = $this->getDataGenerator()->create_user($user1);
490         $user2 = new stdClass();
491         $user2->firstname = 'User';
492         $user2->lastname = 'Two';
493         $user2 = $this->getDataGenerator()->create_user($user2);
495         // Perform a search as user1.
496         $this->setUser($user1);
497         $result = \core_message\api::message_search_users($user1->id, 'search');
499         // Check results are empty.
500         $this->assertCount(0, $result[0]);
501         $this->assertCount(0, $result[1]);
502     }
504     /**
505      * Test verifying that limits and offsets work for both the contacts and non-contacts return data.
506      */
507     public function test_message_search_users_limit_offset() {
508         $this->resetAfterTest();
510         // Create 20 users.
511         $users = [];
512         foreach (range(1, 20) as $i) {
513             $user = new stdClass();
514             $user->firstname = "User search";
515             $user->lastname = $i;
516             $user = $this->getDataGenerator()->create_user($user);
517             $users[$i] = $user;
518         }
520         // Enrol the first 9 users in the same course, but leave them as non-contacts.
521         $this->setAdminUser();
522         $course1 = $this->getDataGenerator()->create_course();
523         foreach (range(1, 9) as $i) {
524             $this->getDataGenerator()->enrol_user($users[$i]->id, $course1->id);
525         }
527         // Add 5 users, starting at the 11th user, as contacts for user1.
528         foreach (range(11, 15) as $i) {
529             \core_message\api::add_contact($users[1]->id, $users[$i]->id);
530         }
532         // Set as the user performing the search.
533         $this->setUser($users[1]);
535         // Search using a limit of 3.
536         // This tests the case where we have more results than the limit for both contacts and non-contacts.
537         $result = \core_message\api::message_search_users($users[1]->id, 'search', 0, 3);
538         $contacts = $result[0];
539         $noncontacts = $result[1];
541         // Check that we retrieved the correct contacts.
542         $this->assertCount(3, $contacts);
543         $this->assertEquals($users[11]->id, $contacts[0]->id);
544         $this->assertEquals($users[12]->id, $contacts[1]->id);
545         $this->assertEquals($users[13]->id, $contacts[2]->id);
547         // Check that we retrieved the correct non-contacts.
548         $this->assertCount(3, $noncontacts);
549         $this->assertEquals($users[2]->id, $noncontacts[0]->id);
550         $this->assertEquals($users[3]->id, $noncontacts[1]->id);
551         $this->assertEquals($users[4]->id, $noncontacts[2]->id);
553         // Now, offset to get the next batch of results.
554         // We expect to see 2 contacts, and 3 non-contacts.
555         $result = \core_message\api::message_search_users($users[1]->id, 'search', 3, 3);
556         $contacts = $result[0];
557         $noncontacts = $result[1];
558         $this->assertCount(2, $contacts);
559         $this->assertEquals($users[14]->id, $contacts[0]->id);
560         $this->assertEquals($users[15]->id, $contacts[1]->id);
562         $this->assertCount(3, $noncontacts);
563         $this->assertEquals($users[5]->id, $noncontacts[0]->id);
564         $this->assertEquals($users[6]->id, $noncontacts[1]->id);
565         $this->assertEquals($users[7]->id, $noncontacts[2]->id);
567         // Now, offset to get the next batch of results.
568         // We expect to see 0 contacts, and 2 non-contacts.
569         $result = \core_message\api::message_search_users($users[1]->id, 'search', 6, 3);
570         $contacts = $result[0];
571         $noncontacts = $result[1];
572         $this->assertCount(0, $contacts);
574         $this->assertCount(2, $noncontacts);
575         $this->assertEquals($users[8]->id, $noncontacts[0]->id);
576         $this->assertEquals($users[9]->id, $noncontacts[1]->id);
577     }
579     /**
580      * Tests searching users as a user having the 'moodle/user:viewdetails' capability.
581      */
582     public function test_message_search_users_with_cap() {
583         $this->resetAfterTest();
584         global $DB;
586         // Create some users.
587         $users = [];
588         foreach (range(1, 8) as $i) {
589             $user = new stdClass();
590             $user->firstname = ($i == 4) ? 'User' : 'User search'; // Ensure the fourth user won't match the search term.
591             $user->lastname = $i;
592             $user = $this->getDataGenerator()->create_user($user);
593             $users[$i] = $user;
594         }
596         // Enrol a few users in the same course, but leave them as non-contacts.
597         $course1 = $this->getDataGenerator()->create_course();
598         $this->setAdminUser();
599         $this->getDataGenerator()->enrol_user($users[1]->id, $course1->id);
600         $this->getDataGenerator()->enrol_user($users[6]->id, $course1->id);
601         $this->getDataGenerator()->enrol_user($users[7]->id, $course1->id);
603         // Add some other users as contacts.
604         \core_message\api::add_contact($users[1]->id, $users[2]->id);
605         \core_message\api::add_contact($users[3]->id, $users[1]->id);
606         \core_message\api::add_contact($users[1]->id, $users[4]->id);
608         // Set as the user performing the search.
609         $this->setUser($users[1]);
611         // Grant the authenticated user role the capability 'user:viewdetails' at site context.
612         $authenticatedrole = $DB->get_record('role', ['shortname' => 'user'], '*', MUST_EXIST);
613         assign_capability('moodle/user:viewdetails', CAP_ALLOW, $authenticatedrole->id, context_system::instance());
615         // Perform a search with $CFG->messagingallusers disabled.
616         set_config('messagingallusers', 0);
617         $result = \core_message\api::message_search_users($users[1]->id, 'search');
618         $contacts = $result[0];
619         $noncontacts = $result[1];
621         // Check that we retrieved the correct contacts.
622         $this->assertCount(2, $contacts);
623         $this->assertEquals($users[2]->id, $contacts[0]->id);
624         $this->assertEquals($users[3]->id, $contacts[1]->id);
626         // Check that we retrieved the correct non-contacts.
627         // Site-wide messaging is disabled, but since we can see all users, we expect to be able to search for any users.
628         $this->assertCount(4, $noncontacts);
629         $this->assertEquals($users[5]->id, $noncontacts[0]->id);
630         $this->assertEquals($users[6]->id, $noncontacts[1]->id);
631         $this->assertEquals($users[7]->id, $noncontacts[2]->id);
632         $this->assertEquals($users[8]->id, $noncontacts[3]->id);
633     }
635     /**
636      * Tests searching users with messaging disabled.
637      */
638     public function test_message_search_users_messaging_disabled() {
639         $this->resetAfterTest();
641         // Create a user.
642         $user = $this->getDataGenerator()->create_user();
644         // Disable messaging.
645         set_config('messaging', 0);
647         // Ensure an exception is thrown.
648         $this->expectException('moodle_exception');
649         \core_message\api::message_search_users($user->id, 'User');
650     }
652     /**
653      * Tests getting conversations between 2 users.
654      */
655     public function test_get_conversations_between_users() {
656         // Create some users.
657         $user1 = new stdClass();
658         $user1->firstname = 'User';
659         $user1->lastname = 'One';
660         $user1 = self::getDataGenerator()->create_user($user1);
662         $user2 = new stdClass();
663         $user2->firstname = 'User';
664         $user2->lastname = 'Two';
665         $user2 = self::getDataGenerator()->create_user($user2);
667         $user3 = new stdClass();
668         $user3->firstname = 'User search';
669         $user3->lastname = 'Three';
670         $user3 = self::getDataGenerator()->create_user($user3);
672         $user4 = new stdClass();
673         $user4->firstname = 'User';
674         $user4->lastname = 'Four';
675         $user4 = self::getDataGenerator()->create_user($user4);
677         $user5 = new stdClass();
678         $user5->firstname = 'User';
679         $user5->lastname = 'Five';
680         $user5 = self::getDataGenerator()->create_user($user5);
682         $user6 = new stdClass();
683         $user6->firstname = 'User search';
684         $user6->lastname = 'Six';
685         $user6 = self::getDataGenerator()->create_user($user6);
687         // Add some users as contacts.
688         \core_message\api::add_contact($user1->id, $user2->id);
689         \core_message\api::add_contact($user6->id, $user1->id);
691         // Create private conversations with some users.
692         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
693             array($user1->id, $user2->id));
694         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
695             array($user3->id, $user1->id));
697         // Create a group conversation with users.
698         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
699             array($user1->id, $user2->id, $user3->id, $user4->id),
700             'Project chat');
702         // Check that we retrieved the correct conversations.
703         $this->assertCount(2, \core_message\api::get_conversations_between_users($user1->id, $user2->id));
704         $this->assertCount(2, \core_message\api::get_conversations_between_users($user2->id, $user1->id));
705         $this->assertCount(2, \core_message\api::get_conversations_between_users($user1->id, $user3->id));
706         $this->assertCount(2, \core_message\api::get_conversations_between_users($user3->id, $user1->id));
707         $this->assertCount(1, \core_message\api::get_conversations_between_users($user1->id, $user4->id));
708         $this->assertCount(1, \core_message\api::get_conversations_between_users($user4->id, $user1->id));
709         $this->assertCount(0, \core_message\api::get_conversations_between_users($user1->id, $user5->id));
710         $this->assertCount(0, \core_message\api::get_conversations_between_users($user5->id, $user1->id));
711         $this->assertCount(0, \core_message\api::get_conversations_between_users($user1->id, $user6->id));
712         $this->assertCount(0, \core_message\api::get_conversations_between_users($user6->id, $user1->id));
713     }
715     /**
716      * Tests searching messages.
717      */
718     public function test_search_messages() {
719         // Create some users.
720         $user1 = self::getDataGenerator()->create_user();
721         $user2 = self::getDataGenerator()->create_user();
722         $user3 = self::getDataGenerator()->create_user();
724         // The person doing the search.
725         $this->setUser($user1);
727         // Send some messages back and forth.
728         $time = 1;
729         $this->send_fake_message($user3, $user1, 'Don\'t block me.', 0, $time);
730         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
731         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
732         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
733         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
735         // Block user 3.
736         \core_message\api::block_user($user1->id, $user3->id);
738         // Perform a search.
739         $messages = \core_message\api::search_messages($user1->id, 'o');
741         // Confirm the data is correct.
742         $this->assertEquals(3, count($messages));
744         $message1 = $messages[0];
745         $message2 = $messages[1];
746         $message3 = $messages[2];
748         $this->assertEquals($user2->id, $message1->userid);
749         $this->assertEquals($user2->id, $message1->useridfrom);
750         $this->assertEquals(fullname($user2), $message1->fullname);
751         $this->assertTrue($message1->ismessaging);
752         $this->assertEquals('Word.', $message1->lastmessage);
753         $this->assertNotEmpty($message1->messageid);
754         $this->assertNull($message1->isonline);
755         $this->assertFalse($message1->isread);
756         $this->assertFalse($message1->isblocked);
757         $this->assertNull($message1->unreadcount);
759         $this->assertEquals($user2->id, $message2->userid);
760         $this->assertEquals($user1->id, $message2->useridfrom);
761         $this->assertEquals(fullname($user2), $message2->fullname);
762         $this->assertTrue($message2->ismessaging);
763         $this->assertEquals('Yo!', $message2->lastmessage);
764         $this->assertNotEmpty($message2->messageid);
765         $this->assertNull($message2->isonline);
766         $this->assertTrue($message2->isread);
767         $this->assertFalse($message2->isblocked);
768         $this->assertNull($message2->unreadcount);
770         $this->assertEquals($user3->id, $message3->userid);
771         $this->assertEquals($user3->id, $message3->useridfrom);
772         $this->assertEquals(fullname($user3), $message3->fullname);
773         $this->assertTrue($message3->ismessaging);
774         $this->assertEquals('Don\'t block me.', $message3->lastmessage);
775         $this->assertNotEmpty($message3->messageid);
776         $this->assertNull($message3->isonline);
777         $this->assertFalse($message3->isread);
778         $this->assertTrue($message3->isblocked);
779         $this->assertNull($message3->unreadcount);
780     }
782     /**
783      * Test verifying that favourited conversations can be retrieved.
784      */
785     public function test_get_favourite_conversations() {
786         // Create some users.
787         $user1 = self::getDataGenerator()->create_user();
788         $user2 = self::getDataGenerator()->create_user();
789         $user3 = self::getDataGenerator()->create_user();
790         $user4 = self::getDataGenerator()->create_user();
792         // The person doing the search.
793         $this->setUser($user1);
795         // No conversations yet.
796         $this->assertEquals([], \core_message\api::get_conversations($user1->id));
798         // Create some conversations for user1.
799         $time = 1;
800         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
801         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
802         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
803         $messageid1 = $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
805         $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
806         $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
807         $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
808         $messageid2 = $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
810         $this->send_fake_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?', 0, $time + 9);
811         $this->send_fake_message($user4, $user1, 'Yah brah, it\'s pretty rad.', 0, $time + 10);
812         $messageid3 = $this->send_fake_message($user1, $user4, 'Dope.', 0, $time + 11);
814         // Favourite the first 2 conversations for user1.
815         $convoids = [];
816         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
817         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]);
818         $user1context = context_user::instance($user1->id);
819         $service = \core_favourites\service_factory::get_service_for_user_context($user1context);
820         foreach ($convoids as $convoid) {
821             $service->create_favourite('core_message', 'message_conversations', $convoid, $user1context);
822         }
824         // We should have 3 conversations.
825         $this->assertCount(3, \core_message\api::get_conversations($user1->id));
827         // And 2 favourited conversations.
828         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, true);
829         $this->assertCount(2, $conversations);
830     }
832     /**
833      * Tests retrieving favourite conversations with a limit and offset to ensure pagination works correctly.
834      */
835     public function test_get_favourite_conversations_limit_offset() {
836         // Create some users.
837         $user1 = self::getDataGenerator()->create_user();
838         $user2 = self::getDataGenerator()->create_user();
839         $user3 = self::getDataGenerator()->create_user();
840         $user4 = self::getDataGenerator()->create_user();
842         // The person doing the search.
843         $this->setUser($user1);
845         // No conversations yet.
846         $this->assertEquals([], \core_message\api::get_conversations($user1->id));
848         // Create some conversations for user1.
849         $time = 1;
850         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
851         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
852         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
853         $messageid1 = $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
855         $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
856         $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
857         $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
858         $messageid2 = $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
860         $this->send_fake_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?', 0, $time + 9);
861         $this->send_fake_message($user4, $user1, 'Yah brah, it\'s pretty rad.', 0, $time + 10);
862         $messageid3 = $this->send_fake_message($user1, $user4, 'Dope.', 0, $time + 11);
864         // Favourite the all conversations for user1.
865         $convoids = [];
866         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
867         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]);
868         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user4->id]);
869         $user1context = context_user::instance($user1->id);
870         $service = \core_favourites\service_factory::get_service_for_user_context($user1context);
871         foreach ($convoids as $convoid) {
872             $service->create_favourite('core_message', 'message_conversations', $convoid, $user1context);
873         }
875         // Get all records, using offset 0 and large limit.
876         $this->assertCount(2, \core_message\api::get_conversations($user1->id, 1, 10, null, true));
878         // Now, get 10 conversations starting at the second record. We should see 2 conversations.
879         $this->assertCount(2, \core_message\api::get_conversations($user1->id, 1, 10, null, true));
881         // Now, try to get favourited conversations using an invalid offset.
882         $this->assertCount(0, \core_message\api::get_conversations($user1->id, 4, 10, null, true));
883     }
885     /**
886      * Tests retrieving favourite conversations when a conversation contains a deleted user.
887      */
888     public function test_get_favourite_conversations_with_deleted_user() {
889         // Create some users.
890         $user1 = self::getDataGenerator()->create_user();
891         $user2 = self::getDataGenerator()->create_user();
892         $user3 = self::getDataGenerator()->create_user();
894         // Send some messages back and forth, have some different conversations with different users.
895         $time = 1;
896         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
897         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
898         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
899         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
901         $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
902         $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
903         $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
904         $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
906         // Favourite the all conversations for user1.
907         $convoids = [];
908         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
909         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]);
910         $user1context = context_user::instance($user1->id);
911         $service = \core_favourites\service_factory::get_service_for_user_context($user1context);
912         foreach ($convoids as $convoid) {
913             $service->create_favourite('core_message', 'message_conversations', $convoid, $user1context);
914         }
916         // Delete the second user.
917         delete_user($user2);
919         // Retrieve the conversations.
920         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, true);
922         // We should only have one conversation because the other user was deleted.
923         $this->assertCount(1, $conversations);
925         // Confirm the conversation is from the non-deleted user.
926         $conversation = reset($conversations);
927         $this->assertEquals($convoids[1], $conversation->id);
928     }
930     /**
931      * Test confirming that conversations can be marked as favourites.
932      */
933     public function test_set_favourite_conversation() {
934         // Create some users.
935         $user1 = self::getDataGenerator()->create_user();
936         $user2 = self::getDataGenerator()->create_user();
937         $user3 = self::getDataGenerator()->create_user();
939         // Send some messages back and forth, have some different conversations with different users.
940         $time = 1;
941         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
942         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
943         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
944         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
946         $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
947         $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
948         $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
949         $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
951         // Favourite the first conversation as user 1.
952         $conversationid1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
953         $favourite = \core_message\api::set_favourite_conversation($conversationid1, $user1->id);
955         // Verify we have a single favourite conversation a user 1.
956         $this->assertCount(1, \core_message\api::get_conversations($user1->id, 0, 20, null, true));
958         // Verify we have no favourites as user2, despite being a member in that conversation.
959         $this->assertCount(0, \core_message\api::get_conversations($user2->id, 0, 20, null, true));
961         // Try to favourite the same conversation again should just return the existing favourite.
962         $repeatresult = \core_message\api::set_favourite_conversation($conversationid1, $user1->id);
963         $this->assertEquals($favourite->id, $repeatresult->id);
964     }
966     /**
967      * Test verifying that trying to mark a non-existent conversation as a favourite, results in an exception.
968      */
969     public function test_set_favourite_conversation_nonexistent_conversation() {
970         // Create some users.
971         $user1 = self::getDataGenerator()->create_user();
972         // Try to favourite a non-existent conversation.
973         $this->expectException(\moodle_exception::class);
974         \core_message\api::set_favourite_conversation(0, $user1->id);
975     }
977     /**
978      * Test verifying that a conversation cannot be marked as favourite unless the user is a member of that conversation.
979      */
980     public function test_set_favourite_conversation_non_member() {
981         // Create some users.
982         $user1 = self::getDataGenerator()->create_user();
983         $user2 = self::getDataGenerator()->create_user();
984         $user3 = self::getDataGenerator()->create_user();
986         // Send some messages back and forth, have some different conversations with different users.
987         $time = 1;
988         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
989         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
990         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
991         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
993         $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
994         $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
995         $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
996         $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
998         // Try to favourite the first conversation as user 3, who is not a member.
999         $conversationid1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
1000         $this->expectException(\moodle_exception::class);
1001         \core_message\api::set_favourite_conversation($conversationid1, $user3->id);
1002     }
1004     /**
1005      * Test confirming that those conversations marked as favourites can be unfavourited.
1006      */
1007     public function test_unset_favourite_conversation() {
1008         // Create some users.
1009         $user1 = self::getDataGenerator()->create_user();
1010         $user2 = self::getDataGenerator()->create_user();
1011         $user3 = self::getDataGenerator()->create_user();
1013         // Send some messages back and forth, have some different conversations with different users.
1014         $time = 1;
1015         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
1016         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
1017         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
1018         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
1020         $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
1021         $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
1022         $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
1023         $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
1025         // Favourite the first conversation as user 1 and the second as user 3.
1026         $conversationid1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
1027         $conversationid2 = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]);
1028         \core_message\api::set_favourite_conversation($conversationid1, $user1->id);
1029         \core_message\api::set_favourite_conversation($conversationid2, $user3->id);
1031         // Verify we have a single favourite conversation for both user 1 and user 3.
1032         $this->assertCount(1, \core_message\api::get_conversations($user1->id, 0, 20, null, true));
1033         $this->assertCount(1, \core_message\api::get_conversations($user3->id, 0, 20, null, true));
1035         // Now unfavourite the conversation as user 1.
1036         \core_message\api::unset_favourite_conversation($conversationid1, $user1->id);
1038         // Verify we have a single favourite conversation user 3 only, and none for user1.
1039         $this->assertCount(1, \core_message\api::get_conversations($user3->id, 0, 20, null, true));
1040         $this->assertCount(0, \core_message\api::get_conversations($user1->id, 0, 20, null, true));
1042         // Try to favourite the same conversation again as user 1.
1043         $this->expectException(\moodle_exception::class);
1044         \core_message\api::unset_favourite_conversation($conversationid1, $user1->id);
1045     }
1047     /**
1048      * Test verifying that a valid conversation cannot be unset as a favourite if it's not marked as a favourite.
1049      */
1050     public function test_unset_favourite_conversation_not_favourite() {
1051         // Create some users.
1052         $user1 = self::getDataGenerator()->create_user();
1053         $user2 = self::getDataGenerator()->create_user();
1055         // Send some messages back and forth, have some different conversations with different users.
1056         $time = 1;
1057         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
1058         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
1059         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
1060         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
1062         // Now try to unfavourite the conversation as user 1.
1063         $conversationid1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
1064         $this->expectException(\moodle_exception::class);
1065         \core_message\api::unset_favourite_conversation($conversationid1, $user1->id);
1066     }
1068     /**
1069      * Test verifying that a non-existent conversation cannot be unset as a favourite.
1070      */
1071     public function test_unset_favourite_conversation_non_existent_conversation() {
1072         // Create some users.
1073         $user1 = self::getDataGenerator()->create_user();
1075         // Now try to unfavourite the conversation as user 1.
1076         $this->expectException(\moodle_exception::class);
1077         \core_message\api::unset_favourite_conversation(0, $user1->id);
1078     }
1080     /**
1081      * Helper to seed the database with initial state.
1082      */
1083     protected function create_conversation_test_data() {
1084         // Create some users.
1085         $user1 = self::getDataGenerator()->create_user();
1086         $user2 = self::getDataGenerator()->create_user();
1087         $user3 = self::getDataGenerator()->create_user();
1088         $user4 = self::getDataGenerator()->create_user();
1090         $time = 1;
1092         // Create some conversations. We want:
1093         // 1) At least one of each type (group, individual) of which user1 IS a member and DID send the most recent message.
1094         // 2) At least one of each type (group, individual) of which user1 IS a member and DID NOT send the most recent message.
1095         // 3) At least one of each type (group, individual) of which user1 IS NOT a member.
1096         // 4) At least two group conversation having 0 messages, of which user1 IS a member (To confirm conversationid ordering).
1097         // 5) At least one group conversation having 0 messages, of which user1 IS NOT a member.
1099         // Individual conversation, user1 is a member, last message from other user.
1100         $ic1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1101             [$user1->id, $user2->id]);
1102         testhelper::send_fake_message_to_conversation($user1, $ic1->id, 'Message 1', $time);
1103         testhelper::send_fake_message_to_conversation($user2, $ic1->id, 'Message 2', $time + 1);
1105         // Individual conversation, user1 is a member, last message from user1.
1106         $ic2 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1107             [$user1->id, $user3->id]);
1108         testhelper::send_fake_message_to_conversation($user3, $ic2->id, 'Message 3', $time + 2);
1109         testhelper::send_fake_message_to_conversation($user1, $ic2->id, 'Message 4', $time + 3);
1111         // Individual conversation, user1 is not a member.
1112         $ic3 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1113             [$user2->id, $user3->id]);
1114         testhelper::send_fake_message_to_conversation($user2, $ic3->id, 'Message 5', $time + 4);
1115         testhelper::send_fake_message_to_conversation($user3, $ic3->id, 'Message 6', $time + 5);
1117         // Group conversation, user1 is not a member.
1118         $gc1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1119             [$user2->id, $user3->id, $user4->id], 'Project discussions');
1120         testhelper::send_fake_message_to_conversation($user2, $gc1->id, 'Message 7', $time + 6);
1121         testhelper::send_fake_message_to_conversation($user4, $gc1->id, 'Message 8', $time + 7);
1123         // Group conversation, user1 is a member, last message from another user.
1124         $gc2 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1125             [$user1->id, $user3->id, $user4->id], 'Group chat');
1126         testhelper::send_fake_message_to_conversation($user1, $gc2->id, 'Message 9', $time + 8);
1127         testhelper::send_fake_message_to_conversation($user3, $gc2->id, 'Message 10', $time + 9);
1128         testhelper::send_fake_message_to_conversation($user4, $gc2->id, 'Message 11', $time + 10);
1130         // Group conversation, user1 is a member, last message from user1.
1131         $gc3 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1132             [$user1->id, $user2->id, $user3->id, $user4->id], 'Group chat again!');
1133         testhelper::send_fake_message_to_conversation($user4, $gc3->id, 'Message 12', $time + 11);
1134         testhelper::send_fake_message_to_conversation($user3, $gc3->id, 'Message 13', $time + 12);
1135         testhelper::send_fake_message_to_conversation($user1, $gc3->id, 'Message 14', $time + 13);
1137         // Empty group conversations (x2), user1 is a member.
1138         $gc4 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1139             [$user1->id, $user2->id, $user3->id], 'Empty group');
1140         $gc5 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1141             [$user1->id, $user2->id, $user4->id], 'Another empty group');
1143         // Empty group conversation, user1 is NOT a member.
1144         $gc6 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1145             [$user2->id, $user3->id, $user4->id], 'Empty group 3');
1147         return [$user1, $user2, $user3, $user4, $ic1, $ic2, $ic3, $gc1, $gc2, $gc3, $gc4, $gc5, $gc6];
1148     }
1150     /**
1151      * Test verifying get_conversations when no limits, offsets, type filters or favourite restrictions are used.
1152      */
1153     public function test_get_conversations_no_restrictions() {
1154         global $DB;
1155         // No conversations should exist yet.
1156         $user1 = self::getDataGenerator()->create_user();
1157         $this->assertEquals([], \core_message\api::get_conversations($user1->id));
1159         // Get a bunch of conversations, some group, some individual and in different states.
1160         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1161             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1163         // Get all conversations for user1.
1164         $conversations = core_message\api::get_conversations($user1->id);
1166         // Verify there are 2 individual conversation, 2 group conversations, and 2 empty group conversations.
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(6, $conversations);
1170         $typecounts  = array_count_values(array_column($conversations, 'type'));
1171         $this->assertEquals(2, $typecounts[1]);
1172         $this->assertEquals(4, $typecounts[2]);
1174         // Those conversations having messages should be listed first, ordered by most recent message time.
1175         $this->assertEquals($gc3->id, $conversations[0]->id);
1176         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $conversations[0]->type);
1177         $this->assertFalse($conversations[0]->isfavourite);
1178         $this->assertCount(1, $conversations[0]->members);
1179         $this->assertEquals(4, $conversations[0]->membercount);
1180         $this->assertCount(1, $conversations[0]->messages);
1181         $message = $DB->get_record('messages', ['id' => $conversations[0]->messages[0]->id]);
1182         $expectedmessagetext = message_format_message_text($message);
1183         $this->assertEquals($expectedmessagetext, $conversations[0]->messages[0]->text);
1184         $this->assertEquals($user1->id, $conversations[0]->messages[0]->useridfrom);
1186         $this->assertEquals($gc2->id, $conversations[1]->id);
1187         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $conversations[1]->type);
1188         $this->assertFalse($conversations[1]->isfavourite);
1189         $this->assertCount(1, $conversations[1]->members);
1190         $this->assertEquals(3, $conversations[1]->membercount);
1191         $this->assertCount(1, $conversations[1]->messages);
1192         $message = $DB->get_record('messages', ['id' => $conversations[1]->messages[0]->id]);
1193         $expectedmessagetext = message_format_message_text($message);
1194         $this->assertEquals($expectedmessagetext, $conversations[1]->messages[0]->text);
1195         $this->assertEquals($user4->id, $conversations[1]->messages[0]->useridfrom);
1197         $this->assertEquals($ic2->id, $conversations[2]->id);
1198         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $conversations[2]->type);
1199         $this->assertFalse($conversations[2]->isfavourite);
1200         $this->assertCount(1, $conversations[2]->members);
1201         $this->assertEquals($user3->id, $conversations[2]->members[$user3->id]->id);
1202         $this->assertEquals(2, $conversations[2]->membercount);
1203         $this->assertCount(1, $conversations[2]->messages);
1204         $message = $DB->get_record('messages', ['id' => $conversations[2]->messages[0]->id]);
1205         $expectedmessagetext = message_format_message_text($message);
1206         $this->assertEquals($expectedmessagetext, $conversations[2]->messages[0]->text);
1207         $this->assertEquals($user1->id, $conversations[2]->messages[0]->useridfrom);
1209         $this->assertEquals($ic1->id, $conversations[3]->id);
1210         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $conversations[3]->type);
1211         $this->assertFalse($conversations[3]->isfavourite);
1212         $this->assertCount(1, $conversations[3]->members);
1213         $this->assertEquals(2, $conversations[3]->membercount);
1214         $this->assertCount(1, $conversations[3]->messages);
1215         $message = $DB->get_record('messages', ['id' => $conversations[3]->messages[0]->id]);
1216         $expectedmessagetext = message_format_message_text($message);
1217         $this->assertEquals($expectedmessagetext, $conversations[3]->messages[0]->text);
1218         $this->assertEquals($user2->id, $conversations[3]->messages[0]->useridfrom);
1220         // Of the groups without messages, we expect to see the most recently created first.
1221         $this->assertEquals($gc5->id, $conversations[4]->id);
1222         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $conversations[4]->type);
1223         $this->assertFalse($conversations[4]->isfavourite);
1224         $this->assertCount(0, $conversations[4]->members); // No members returned, because no recent messages exist.
1225         $this->assertEquals(3, $conversations[4]->membercount);
1226         $this->assertEmpty($conversations[4]->messages);
1228         $this->assertEquals($gc4->id, $conversations[5]->id);
1229         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $conversations[5]->type);
1230         $this->assertFalse($conversations[5]->isfavourite);
1231         $this->assertCount(0, $conversations[5]->members);
1232         $this->assertEquals(3, $conversations[5]->membercount);
1233         $this->assertEmpty($conversations[5]->messages);
1235         // Verify format of the return structure.
1236         foreach ($conversations as $conv) {
1237             $this->assertObjectHasAttribute('id', $conv);
1238             $this->assertObjectHasAttribute('name', $conv);
1239             $this->assertObjectHasAttribute('subname', $conv);
1240             $this->assertObjectHasAttribute('imageurl', $conv);
1241             $this->assertObjectHasAttribute('type', $conv);
1242             $this->assertObjectHasAttribute('isfavourite', $conv);
1243             $this->assertObjectHasAttribute('membercount', $conv);
1244             $this->assertObjectHasAttribute('isread', $conv);
1245             $this->assertObjectHasAttribute('unreadcount', $conv);
1246             $this->assertObjectHasAttribute('members', $conv);
1247             foreach ($conv->members as $member) {
1248                 $this->assertObjectHasAttribute('id', $member);
1249                 $this->assertObjectHasAttribute('fullname', $member);
1250                 $this->assertObjectHasAttribute('profileimageurl', $member);
1251                 $this->assertObjectHasAttribute('profileimageurlsmall', $member);
1252                 $this->assertObjectHasAttribute('isonline', $member);
1253                 $this->assertObjectHasAttribute('showonlinestatus', $member);
1254                 $this->assertObjectHasAttribute('isblocked', $member);
1255                 $this->assertObjectHasAttribute('iscontact', $member);
1256                 $this->assertObjectHasAttribute('isdeleted', $member);
1257                 $this->assertObjectHasAttribute('canmessage', $member);
1258                 $this->assertObjectHasAttribute('requirescontact', $member);
1259                 $this->assertObjectHasAttribute('contactrequests', $member);
1260             }
1261             $this->assertObjectHasAttribute('messages', $conv);
1262             foreach ($conv->messages as $message) {
1263                 $this->assertObjectHasAttribute('id', $message);
1264                 $this->assertObjectHasAttribute('useridfrom', $message);
1265                 $this->assertObjectHasAttribute('text', $message);
1266                 $this->assertObjectHasAttribute('timecreated', $message);
1267             }
1268         }
1269     }
1271     /**
1272      * Test verifying that html format messages are supported, and that message_format_message_text() is being called appropriately.
1273      */
1274     public function test_get_conversations_message_format() {
1275         global $DB;
1276         // Create some users.
1277         $user1 = self::getDataGenerator()->create_user();
1278         $user2 = self::getDataGenerator()->create_user();
1280         // Create conversation.
1281         $conversation = \core_message\api::create_conversation(
1282             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1283             [$user1->id, $user2->id]
1284         );
1286         // Send some messages back and forth.
1287         $time = 1;
1288         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 1);
1289         $mid = testhelper::send_fake_message_to_conversation($user1, $conversation->id, '<a href="#">A link</a>', $time + 2);
1291         // Verify the format of the html message.
1292         $message = $DB->get_record('messages', ['id' => $mid]);
1293         $expectedmessagetext = message_format_message_text($message);
1294         $conversations = \core_message\api::get_conversations($user1->id);
1295         $messages = $conversations[0]->messages;
1296         $this->assertEquals($expectedmessagetext, $messages[0]->text);
1297     }
1299     /**
1300      * Tests retrieving conversations with a limit and offset to ensure pagination works correctly.
1301      */
1302     public function test_get_conversations_limit_offset() {
1303         // Get a bunch of conversations, some group, some individual and in different states.
1304         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1305             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1307         // Get all conversations for user1, limited to 1 result.
1308         $conversations = core_message\api::get_conversations($user1->id, 0, 1);
1310         // Verify the first conversation.
1311         $this->assertCount(1, $conversations);
1312         $conversation = array_shift($conversations);
1313         $this->assertEquals($conversation->id, $gc3->id);
1315         // Verify the next conversation.
1316         $conversations = \core_message\api::get_conversations($user1->id, 1, 1);
1317         $this->assertCount(1, $conversations);
1318         $this->assertEquals($gc2->id, $conversations[0]->id);
1320         // Verify the next conversation.
1321         $conversations = \core_message\api::get_conversations($user1->id, 2, 1);
1322         $this->assertCount(1, $conversations);
1323         $this->assertEquals($ic2->id, $conversations[0]->id);
1325         // Skip one and get both empty conversations.
1326         $conversations = \core_message\api::get_conversations($user1->id, 4, 2);
1327         $this->assertCount(2, $conversations);
1328         $this->assertEquals($gc5->id, $conversations[0]->id);
1329         $this->assertEmpty($conversations[0]->messages);
1330         $this->assertEquals($gc4->id, $conversations[1]->id);
1331         $this->assertEmpty($conversations[1]->messages);
1333         // Ask for an offset that doesn't exist and verify no conversations are returned.
1334         $conversations = \core_message\api::get_conversations($user1->id, 10, 1);
1335         $this->assertCount(0, $conversations);
1336     }
1338     /**
1339      * Test verifying the type filtering behaviour of the
1340      */
1341     public function test_get_conversations_type_filter() {
1342         // Get a bunch of conversations, some group, some individual and in different states.
1343         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1344             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1346         // Verify we can ask for only individual conversations.
1347         $conversations = \core_message\api::get_conversations($user1->id, 0, 20,
1348             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL);
1349         $this->assertCount(2, $conversations);
1351         // Verify we can ask for only group conversations.
1352         $conversations = \core_message\api::get_conversations($user1->id, 0, 20,
1353             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP);
1354         $this->assertCount(4, $conversations);
1356         // Verify an exception is thrown if an unrecognized type is specified.
1357         $this->expectException(\moodle_exception::class);
1358         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, 0);
1359     }
1361     /**
1362      * Tests retrieving conversations when a conversation contains a deleted user.
1363      */
1364     public function test_get_conversations_with_deleted_user() {
1365         // Get a bunch of conversations, some group, some individual and in different states.
1366         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1367             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1369         // Delete the second user and retrieve the conversations.
1370         // We should have 5, as $ic1 drops off the list.
1371         // Group conversations remain albeit with less members.
1372         delete_user($user2);
1373         $conversations = \core_message\api::get_conversations($user1->id);
1374         $this->assertCount(5, $conversations);
1375         $this->assertEquals($gc3->id, $conversations[0]->id);
1376         $this->assertcount(1, $conversations[0]->members);
1377         $this->assertEquals($gc2->id, $conversations[1]->id);
1378         $this->assertcount(1, $conversations[1]->members);
1379         $this->assertEquals($ic2->id, $conversations[2]->id);
1380         $this->assertEquals($gc5->id, $conversations[3]->id);
1381         $this->assertEquals($gc4->id, $conversations[4]->id);
1383         // Delete a user from a group conversation where that user had sent the most recent message.
1384         // This user will still be present in the members array, as will the message in the messages array.
1385         delete_user($user4);
1386         $conversations = \core_message\api::get_conversations($user1->id);
1387         $this->assertCount(5, $conversations);
1388         $this->assertEquals($gc2->id, $conversations[1]->id);
1389         $this->assertcount(1, $conversations[1]->members);
1390         $this->assertEquals($user4->id, $conversations[1]->members[$user4->id]->id);
1391         $this->assertcount(1, $conversations[1]->messages);
1392         $this->assertEquals($user4->id, $conversations[1]->messages[0]->useridfrom);
1394         // Delete the third user and retrieve the conversations.
1395         // We should have 4, as $ic1, $ic2 drop off the list.
1396         // Group conversations remain albeit with less members.
1397         delete_user($user3);
1398         $conversations = \core_message\api::get_conversations($user1->id);
1399         $this->assertCount(4, $conversations);
1400         $this->assertEquals($gc3->id, $conversations[0]->id);
1401         $this->assertcount(1, $conversations[0]->members);
1402         $this->assertEquals($gc2->id, $conversations[1]->id);
1403         $this->assertcount(1, $conversations[1]->members);
1404         $this->assertEquals($gc5->id, $conversations[2]->id);
1405         $this->assertEquals($gc4->id, $conversations[3]->id);
1406     }
1408     /**
1409      * Test confirming the behaviour of get_conversations() when users delete all messages.
1410      */
1411     public function test_get_conversations_deleted_messages() {
1412         // Get a bunch of conversations, some group, some individual and in different states.
1413         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1414             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1416         $conversations = \core_message\api::get_conversations($user1->id);
1417         $this->assertCount(6, $conversations);
1419         // Delete all messages from a group conversation the user is in - it should be returned.
1420         $this->assertTrue(\core_message\api::is_user_in_conversation($user1->id, $gc2->id));
1421         $convmessages = \core_message\api::get_conversation_messages($user1->id, $gc2->id);
1422         $messages = $convmessages['messages'];
1423         foreach ($messages as $message) {
1424             \core_message\api::delete_message($user1->id, $message->id);
1425         }
1426         $conversations = \core_message\api::get_conversations($user1->id);
1427         $this->assertCount(6, $conversations);
1428         $this->assertContains($gc2->id, array_column($conversations, 'id'));
1430         // Delete all messages from an individual conversation the user is in - it should not be returned.
1431         $this->assertTrue(\core_message\api::is_user_in_conversation($user1->id, $ic1->id));
1432         $convmessages = \core_message\api::get_conversation_messages($user1->id, $ic1->id);
1433         $messages = $convmessages['messages'];
1434         foreach ($messages as $message) {
1435             \core_message\api::delete_message($user1->id, $message->id);
1436         }
1437         $conversations = \core_message\api::get_conversations($user1->id);
1438         $this->assertCount(5, $conversations);
1439         $this->assertNotContains($ic1->id, array_column($conversations, 'id'));
1440     }
1442     /**
1443      * Test verifying the behaviour of get_conversations() when fetching favourite conversations with only a single
1444      * favourite.
1445      */
1446     public function test_get_conversations_favourite_conversations_single() {
1447         // Get a bunch of conversations, some group, some individual and in different states.
1448         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1449             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1451         // Mark a single conversation as favourites.
1452         \core_message\api::set_favourite_conversation($ic2->id, $user1->id);
1454         // Get the conversation, first with no restrictions, confirming the favourite status of the conversations.
1455         $conversations = \core_message\api::get_conversations($user1->id);
1456         $this->assertCount(6, $conversations);
1457         foreach ($conversations as $conv) {
1458             if (in_array($conv->id, [$ic2->id])) {
1459                 $this->assertTrue($conv->isfavourite);
1460             } else {
1461                 $this->assertFalse($conv->isfavourite);
1462             }
1463         }
1465         // Now, get ONLY favourite conversations.
1466         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, true);
1467         $this->assertCount(1, $conversations);
1468         foreach ($conversations as $conv) {
1469             $this->assertTrue($conv->isfavourite);
1470             $this->assertEquals($ic2->id, $conv->id);
1471         }
1473         // Now, try ONLY favourites of type 'group'.
1474         $conversations = \core_message\api::get_conversations($user1->id, 0, 20,
1475             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, true);
1476         $this->assertEmpty($conversations);
1478         // And NO favourite conversations.
1479         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, false);
1480         $this->assertCount(5, $conversations);
1481         foreach ($conversations as $conv) {
1482             $this->assertFalse($conv->isfavourite);
1483             $this->assertNotEquals($ic2, $conv->id);
1484         }
1485     }
1487     /**
1488      * Test verifying the behaviour of get_conversations() when fetching favourite conversations.
1489      */
1490     public function test_get_conversations_favourite_conversations() {
1491         // Get a bunch of conversations, some group, some individual and in different states.
1492         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1493             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1495         // Try to get ONLY favourite conversations, when no favourites exist.
1496         $this->assertEquals([], \core_message\api::get_conversations($user1->id, 0, 20, null, true));
1498         // Try to get NO favourite conversations, when no favourites exist.
1499         $this->assertCount(6, \core_message\api::get_conversations($user1->id, 0, 20, null, false));
1501         // Mark a few conversations as favourites.
1502         \core_message\api::set_favourite_conversation($ic1->id, $user1->id);
1503         \core_message\api::set_favourite_conversation($gc2->id, $user1->id);
1504         \core_message\api::set_favourite_conversation($gc5->id, $user1->id);
1505         $favouriteids = [$ic1->id, $gc2->id, $gc5->id];
1507         // Get the conversations, first with no restrictions, confirming the favourite status of the conversations.
1508         $conversations = \core_message\api::get_conversations($user1->id);
1509         $this->assertCount(6, $conversations);
1510         foreach ($conversations as $conv) {
1511             if (in_array($conv->id, $favouriteids)) {
1512                 $this->assertTrue($conv->isfavourite);
1513             } else {
1514                 $this->assertFalse($conv->isfavourite);
1515             }
1516         }
1518         // Now, get ONLY favourite conversations.
1519         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, true);
1520         $this->assertCount(3, $conversations);
1521         foreach ($conversations as $conv) {
1522             $this->assertTrue($conv->isfavourite);
1523             $this->assertNotFalse(array_search($conv->id, $favouriteids));
1524         }
1526         // Now, try ONLY favourites of type 'group'.
1527         $conversations = \core_message\api::get_conversations($user1->id, 0, 20,
1528             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, true);
1529         $this->assertCount(2, $conversations);
1530         foreach ($conversations as $conv) {
1531             $this->assertTrue($conv->isfavourite);
1532             $this->assertNotFalse(array_search($conv->id, [$gc2->id, $gc5->id]));
1533         }
1535         // And NO favourite conversations.
1536         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, false);
1537         $this->assertCount(3, $conversations);
1538         foreach ($conversations as $conv) {
1539             $this->assertFalse($conv->isfavourite);
1540             $this->assertFalse(array_search($conv->id, $favouriteids));
1541         }
1542     }
1544     /**
1545      * Test verifying get_conversations when there are users in a group and/or individual conversation. The reason this
1546      * test is performed is because we do not need as much data for group conversations (saving DB calls), so we want
1547      * to confirm this happens.
1548      */
1549     public function test_get_conversations_user_in_group_and_individual_chat() {
1550         $this->resetAfterTest();
1552         $user1 = self::getDataGenerator()->create_user();
1553         $user2 = self::getDataGenerator()->create_user();
1554         $user3 = self::getDataGenerator()->create_user();
1556         $conversation = \core_message\api::create_conversation(
1557             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1558             [
1559                 $user1->id,
1560                 $user2->id
1561             ],
1562             'Individual conversation'
1563         );
1565         testhelper::send_fake_message_to_conversation($user1, $conversation->id);
1567         $conversation = \core_message\api::create_conversation(
1568             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1569             [
1570                 $user1->id,
1571                 $user2->id,
1572             ],
1573             'Group conversation'
1574         );
1576         testhelper::send_fake_message_to_conversation($user1, $conversation->id);
1578         \core_message\api::create_contact_request($user1->id, $user2->id);
1579         \core_message\api::create_contact_request($user1->id, $user3->id);
1581         $conversations = \core_message\api::get_conversations($user2->id);
1583         $groupconversation = array_shift($conversations);
1584         $individualconversation = array_shift($conversations);
1586         $this->assertEquals('Group conversation', $groupconversation->name);
1587         $this->assertEquals('Individual conversation', $individualconversation->name);
1589         $this->assertCount(1, $groupconversation->members);
1590         $this->assertCount(1, $individualconversation->members);
1592         $groupmember = reset($groupconversation->members);
1593         $this->assertNull($groupmember->requirescontact);
1594         $this->assertNull($groupmember->canmessage);
1595         $this->assertEmpty($groupmember->contactrequests);
1597         $individualmember = reset($individualconversation->members);
1598         $this->assertNotNull($individualmember->requirescontact);
1599         $this->assertNotNull($individualmember->canmessage);
1600         $this->assertNotEmpty($individualmember->contactrequests);
1601     }
1603     /**
1604      * Test verifying that group linked conversations are returned and contain a subname matching the course name.
1605      */
1606     public function test_get_conversations_group_linked() {
1607         global $CFG;
1609         // Create some users.
1610         $user1 = self::getDataGenerator()->create_user();
1611         $user2 = self::getDataGenerator()->create_user();
1612         $user3 = self::getDataGenerator()->create_user();
1614         $course1 = $this->getDataGenerator()->create_course();
1616         // Create a group with a linked conversation and a valid image.
1617         $this->setAdminUser();
1618         $this->getDataGenerator()->enrol_user($user1->id, $course1->id);
1619         $this->getDataGenerator()->enrol_user($user2->id, $course1->id);
1620         $this->getDataGenerator()->enrol_user($user3->id, $course1->id);
1621         $group1 = $this->getDataGenerator()->create_group([
1622             'courseid' => $course1->id,
1623             'enablemessaging' => 1,
1624             'picturepath' => $CFG->dirroot . '/lib/tests/fixtures/gd-logo.png'
1625         ]);
1627         // Add users to group1.
1628         $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user1->id));
1629         $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user2->id));
1631         // Verify the group with the image works as expected.
1632         $conversations = \core_message\api::get_conversations($user1->id);
1633         $this->assertEquals(2, $conversations[0]->membercount);
1634         $this->assertEquals($course1->shortname, $conversations[0]->subname);
1635         $groupimageurl = get_group_picture_url($group1, $group1->courseid, true);
1636         $this->assertEquals($groupimageurl, $conversations[0]->imageurl);
1638         // Create a group with a linked conversation and without any image.
1639         $group2 = $this->getDataGenerator()->create_group([
1640             'courseid' => $course1->id,
1641             'enablemessaging' => 1,
1642         ]);
1644         // Add users to group2.
1645         $this->getDataGenerator()->create_group_member(array('groupid' => $group2->id, 'userid' => $user2->id));
1646         $this->getDataGenerator()->create_group_member(array('groupid' => $group2->id, 'userid' => $user3->id));
1648         // Verify the group without any image works as expected too.
1649         $conversations = \core_message\api::get_conversations($user3->id);
1650         $this->assertEquals(2, $conversations[0]->membercount);
1651         $this->assertEquals($course1->shortname, $conversations[0]->subname);
1652         $groupimageurl = get_group_picture_url($group2, $group2->courseid, true);
1653         $this->assertEquals($groupimageurl, $conversations[0]->imageurl);
1654     }
1656    /**
1657     * The data provider for get_conversations_mixed.
1658     *
1659     * This provides sets of data to for testing.
1660     * @return array
1661     */
1662    public function get_conversations_mixed_provider() {
1663        return array(
1664             'Test that conversations with messages contacts is correctly ordered.' => array(
1665                 'users' => array(
1666                     'user1',
1667                     'user2',
1668                     'user3',
1669                 ),
1670                 'contacts' => array(
1671                 ),
1672                 'messages' => array(
1673                     array(
1674                         'from'          => 'user1',
1675                         'to'            => 'user2',
1676                         'state'         => 'unread',
1677                         'subject'       => 'S1',
1678                     ),
1679                     array(
1680                         'from'          => 'user2',
1681                         'to'            => 'user1',
1682                         'state'         => 'unread',
1683                         'subject'       => 'S2',
1684                     ),
1685                     array(
1686                         'from'          => 'user1',
1687                         'to'            => 'user2',
1688                         'state'         => 'unread',
1689                         'timecreated'   => 0,
1690                         'subject'       => 'S3',
1691                     ),
1692                     array(
1693                         'from'          => 'user1',
1694                         'to'            => 'user3',
1695                         'state'         => 'read',
1696                         'timemodifier'  => 1,
1697                         'subject'       => 'S4',
1698                     ),
1699                     array(
1700                         'from'          => 'user3',
1701                         'to'            => 'user1',
1702                         'state'         => 'read',
1703                         'timemodifier'  => 1,
1704                         'subject'       => 'S5',
1705                     ),
1706                     array(
1707                         'from'          => 'user1',
1708                         'to'            => 'user3',
1709                         'state'         => 'read',
1710                         'timecreated'   => 0,
1711                         'subject'       => 'S6',
1712                     ),
1713                 ),
1714                 'expectations' => array(
1715                     'user1' => array(
1716                         // User1 has conversed most recently with user3. The most recent message is M5.
1717                         array(
1718                             'messageposition'   => 0,
1719                             'with'              => 'user3',
1720                             'subject'           => '<p>S5</p>',
1721                             'unreadcount'       => 0,
1722                         ),
1723                         // User1 has also conversed with user2. The most recent message is S2.
1724                         array(
1725                             'messageposition'   => 1,
1726                             'with'              => 'user2',
1727                             'subject'           => '<p>S2</p>',
1728                             'unreadcount'       => 1,
1729                         ),
1730                     ),
1731                     'user2' => array(
1732                         // User2 has only conversed with user1. Their most recent shared message was S2.
1733                         array(
1734                             'messageposition'   => 0,
1735                             'with'              => 'user1',
1736                             'subject'           => '<p>S2</p>',
1737                             'unreadcount'       => 2,
1738                         ),
1739                     ),
1740                     'user3' => array(
1741                         // User3 has only conversed with user1. Their most recent shared message was S5.
1742                         array(
1743                             'messageposition'   => 0,
1744                             'with'              => 'user1',
1745                             'subject'           => '<p>S5</p>',
1746                             'unreadcount'       => 0,
1747                         ),
1748                     ),
1749                 ),
1750             ),
1751             'Test conversations with a single user, where some messages are read and some are not.' => array(
1752                 'users' => array(
1753                     'user1',
1754                     'user2',
1755                 ),
1756                 'contacts' => array(
1757                 ),
1758                 'messages' => array(
1759                     array(
1760                         'from'          => 'user1',
1761                         'to'            => 'user2',
1762                         'state'         => 'read',
1763                         'subject'       => 'S1',
1764                     ),
1765                     array(
1766                         'from'          => 'user2',
1767                         'to'            => 'user1',
1768                         'state'         => 'read',
1769                         'subject'       => 'S2',
1770                     ),
1771                     array(
1772                         'from'          => 'user1',
1773                         'to'            => 'user2',
1774                         'state'         => 'unread',
1775                         'timemodifier'  => 1,
1776                         'subject'       => 'S3',
1777                     ),
1778                     array(
1779                         'from'          => 'user1',
1780                         'to'            => 'user2',
1781                         'state'         => 'unread',
1782                         'timemodifier'  => 1,
1783                         'subject'       => 'S4',
1784                     ),
1785                 ),
1786                 'expectations' => array(
1787                     // The most recent message between user1 and user2 was S4.
1788                     'user1' => array(
1789                         array(
1790                             'messageposition'   => 0,
1791                             'with'              => 'user2',
1792                             'subject'           => '<p>S4</p>',
1793                             'unreadcount'       => 0,
1794                         ),
1795                     ),
1796                     'user2' => array(
1797                         // The most recent message between user1 and user2 was S4.
1798                         array(
1799                             'messageposition'   => 0,
1800                             'with'              => 'user1',
1801                             'subject'           => '<p>S4</p>',
1802                             'unreadcount'       => 2,
1803                         ),
1804                     ),
1805                 ),
1806             ),
1807             'Test conversations with a single user, where some messages are read and some are not, and messages ' .
1808             'are out of order' => array(
1809             // This can happen through a combination of factors including multi-master DB replication with messages
1810             // read somehow (e.g. API).
1811                 'users' => array(
1812                     'user1',
1813                     'user2',
1814                 ),
1815                 'contacts' => array(
1816                 ),
1817                 'messages' => array(
1818                     array(
1819                         'from'          => 'user1',
1820                         'to'            => 'user2',
1821                         'state'         => 'read',
1822                         'subject'       => 'S1',
1823                         'timemodifier'  => 1,
1824                     ),
1825                     array(
1826                         'from'          => 'user2',
1827                         'to'            => 'user1',
1828                         'state'         => 'read',
1829                         'subject'       => 'S2',
1830                         'timemodifier'  => 2,
1831                     ),
1832                     array(
1833                         'from'          => 'user1',
1834                         'to'            => 'user2',
1835                         'state'         => 'unread',
1836                         'subject'       => 'S3',
1837                     ),
1838                     array(
1839                         'from'          => 'user1',
1840                         'to'            => 'user2',
1841                         'state'         => 'unread',
1842                         'subject'       => 'S4',
1843                     ),
1844                 ),
1845                 'expectations' => array(
1846                     // The most recent message between user1 and user2 was S2, even though later IDs have not been read.
1847                     'user1' => array(
1848                         array(
1849                             'messageposition'   => 0,
1850                             'with'              => 'user2',
1851                             'subject'           => '<p>S2</p>',
1852                             'unreadcount'       => 0,
1853                         ),
1854                     ),
1855                     'user2' => array(
1856                         array(
1857                             'messageposition'   => 0,
1858                             'with'              => 'user1',
1859                             'subject'           => '<p>S2</p>',
1860                             'unreadcount'       => 2
1861                         ),
1862                     ),
1863                 ),
1864             ),
1865             'Test unread message count is correct for both users' => array(
1866                 'users' => array(
1867                     'user1',
1868                     'user2',
1869                 ),
1870                 'contacts' => array(
1871                 ),
1872                 'messages' => array(
1873                     array(
1874                         'from'          => 'user1',
1875                         'to'            => 'user2',
1876                         'state'         => 'read',
1877                         'subject'       => 'S1',
1878                         'timemodifier'  => 1,
1879                     ),
1880                     array(
1881                         'from'          => 'user2',
1882                         'to'            => 'user1',
1883                         'state'         => 'read',
1884                         'subject'       => 'S2',
1885                         'timemodifier'  => 2,
1886                     ),
1887                     array(
1888                         'from'          => 'user1',
1889                         'to'            => 'user2',
1890                         'state'         => 'read',
1891                         'subject'       => 'S3',
1892                         'timemodifier'  => 3,
1893                     ),
1894                     array(
1895                         'from'          => 'user1',
1896                         'to'            => 'user2',
1897                         'state'         => 'read',
1898                         'subject'       => 'S4',
1899                         'timemodifier'  => 4,
1900                     ),
1901                     array(
1902                         'from'          => 'user1',
1903                         'to'            => 'user2',
1904                         'state'         => 'unread',
1905                         'subject'       => 'S5',
1906                         'timemodifier'  => 5,
1907                     ),
1908                     array(
1909                         'from'          => 'user2',
1910                         'to'            => 'user1',
1911                         'state'         => 'unread',
1912                         'subject'       => 'S6',
1913                         'timemodifier'  => 6,
1914                     ),
1915                     array(
1916                         'from'          => 'user1',
1917                         'to'            => 'user2',
1918                         'state'         => 'unread',
1919                         'subject'       => 'S7',
1920                         'timemodifier'  => 7,
1921                     ),
1922                     array(
1923                         'from'          => 'user1',
1924                         'to'            => 'user2',
1925                         'state'         => 'unread',
1926                         'subject'       => 'S8',
1927                         'timemodifier'  => 8,
1928                     ),
1929                 ),
1930                 'expectations' => array(
1931                     // The most recent message between user1 and user2 was S2, even though later IDs have not been read.
1932                     'user1' => array(
1933                         array(
1934                             'messageposition'   => 0,
1935                             'with'              => 'user2',
1936                             'subject'           => '<p>S8</p>',
1937                             'unreadcount'       => 1,
1938                         ),
1939                     ),
1940                     'user2' => array(
1941                         array(
1942                             'messageposition'   => 0,
1943                             'with'              => 'user1',
1944                             'subject'           => '<p>S8</p>',
1945                             'unreadcount'       => 3,
1946                         ),
1947                     ),
1948                 ),
1949             ),
1950         );
1951     }
1953     /**
1954      * Test get_conversations with a mixture of messages.
1955      *
1956      * @dataProvider get_conversations_mixed_provider
1957      * @param array $usersdata The list of users to create for this test.
1958      * @param array $messagesdata The list of messages to create.
1959      * @param array $expectations The list of expected outcomes.
1960      */
1961     public function test_get_conversations_mixed($usersdata, $contacts, $messagesdata, $expectations) {
1962         global $DB;
1964         // Create all of the users.
1965         $users = array();
1966         foreach ($usersdata as $username) {
1967             $users[$username] = $this->getDataGenerator()->create_user(array('username' => $username));
1968         }
1970         foreach ($contacts as $username => $contact) {
1971             foreach ($contact as $contactname => $blocked) {
1972                 $record = new stdClass();
1973                 $record->userid     = $users[$username]->id;
1974                 $record->contactid  = $users[$contactname]->id;
1975                 $record->blocked    = $blocked;
1976                 $record->id = $DB->insert_record('message_contacts', $record);
1977             }
1978         }
1980         $defaulttimecreated = time();
1981         foreach ($messagesdata as $messagedata) {
1982             $from       = $users[$messagedata['from']];
1983             $to         = $users[$messagedata['to']];
1984             $subject    = $messagedata['subject'];
1986             if (isset($messagedata['state']) && $messagedata['state'] == 'unread') {
1987                 $messageid = $this->send_fake_message($from, $to, $subject);
1988             } else {
1989                 // If there is no state, or the state is not 'unread', assume the message is read.
1990                 $messageid = message_post_message($from, $to, $subject, FORMAT_PLAIN);
1991             }
1993             $updatemessage = new stdClass();
1994             $updatemessage->id = $messageid;
1995             if (isset($messagedata['timecreated'])) {
1996                 $updatemessage->timecreated = $messagedata['timecreated'];
1997             } else if (isset($messagedata['timemodifier'])) {
1998                 $updatemessage->timecreated = $defaulttimecreated + $messagedata['timemodifier'];
1999             } else {
2000                 $updatemessage->timecreated = $defaulttimecreated;
2001             }
2003             $DB->update_record('messages', $updatemessage);
2004         }
2006         foreach ($expectations as $username => $data) {
2007             // Get the recent conversations for the specified user.
2008             $user = $users[$username];
2009             $conversations = array_values(\core_message\api::get_conversations($user->id));
2010             foreach ($data as $expectation) {
2011                 $otheruser = $users[$expectation['with']];
2012                 $conversation = $conversations[$expectation['messageposition']];
2013                 $this->assertEquals($otheruser->id, $conversation->members[$otheruser->id]->id);
2014                 $this->assertEquals($expectation['subject'], $conversation->messages[0]->text);
2015                 $this->assertEquals($expectation['unreadcount'], $conversation->unreadcount);
2016             }
2017         }
2018     }
2020     /**
2021      * Tests retrieving contacts.
2022      */
2023     public function test_get_contacts() {
2024         // Create some users.
2025         $user1 = self::getDataGenerator()->create_user();
2027         // Set as the user.
2028         $this->setUser($user1);
2030         $user2 = new stdClass();
2031         $user2->firstname = 'User';
2032         $user2->lastname = 'A';
2033         $user2 = self::getDataGenerator()->create_user($user2);
2035         $user3 = new stdClass();
2036         $user3->firstname = 'User';
2037         $user3->lastname = 'B';
2038         $user3 = self::getDataGenerator()->create_user($user3);
2040         $user4 = new stdClass();
2041         $user4->firstname = 'User';
2042         $user4->lastname = 'C';
2043         $user4 = self::getDataGenerator()->create_user($user4);
2045         $user5 = new stdClass();
2046         $user5->firstname = 'User';
2047         $user5->lastname = 'D';
2048         $user5 = self::getDataGenerator()->create_user($user5);
2050         // Add some users as contacts.
2051         \core_message\api::add_contact($user1->id, $user2->id);
2052         \core_message\api::add_contact($user1->id, $user3->id);
2053         \core_message\api::add_contact($user1->id, $user4->id);
2055         // Retrieve the contacts.
2056         $contacts = \core_message\api::get_contacts($user1->id);
2058         // Confirm the data is correct.
2059         $this->assertEquals(3, count($contacts));
2060         usort($contacts, ['static', 'sort_contacts']);
2062         $contact1 = $contacts[0];
2063         $contact2 = $contacts[1];
2064         $contact3 = $contacts[2];
2066         $this->assertEquals($user2->id, $contact1->userid);
2067         $this->assertEmpty($contact1->useridfrom);
2068         $this->assertFalse($contact1->ismessaging);
2069         $this->assertNull($contact1->lastmessage);
2070         $this->assertNull($contact1->messageid);
2071         $this->assertNull($contact1->isonline);
2072         $this->assertFalse($contact1->isread);
2073         $this->assertFalse($contact1->isblocked);
2074         $this->assertNull($contact1->unreadcount);
2076         $this->assertEquals($user3->id, $contact2->userid);
2077         $this->assertEmpty($contact2->useridfrom);
2078         $this->assertFalse($contact2->ismessaging);
2079         $this->assertNull($contact2->lastmessage);
2080         $this->assertNull($contact2->messageid);
2081         $this->assertNull($contact2->isonline);
2082         $this->assertFalse($contact2->isread);
2083         $this->assertFalse($contact2->isblocked);
2084         $this->assertNull($contact2->unreadcount);
2086         $this->assertEquals($user4->id, $contact3->userid);
2087         $this->assertEmpty($contact3->useridfrom);
2088         $this->assertFalse($contact3->ismessaging);
2089         $this->assertNull($contact3->lastmessage);
2090         $this->assertNull($contact3->messageid);
2091         $this->assertNull($contact3->isonline);
2092         $this->assertFalse($contact3->isread);
2093         $this->assertFalse($contact3->isblocked);
2094         $this->assertNull($contact3->unreadcount);
2095     }
2097     /**
2098      * Tests retrieving messages.
2099      */
2100     public function test_get_messages() {
2101         // Create some users.
2102         $user1 = self::getDataGenerator()->create_user();
2103         $user2 = self::getDataGenerator()->create_user();
2105         // The person doing the search.
2106         $this->setUser($user1);
2108         // Send some messages back and forth.
2109         $time = 1;
2110         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
2111         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
2112         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
2113         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
2115         // Retrieve the messages.
2116         $messages = \core_message\api::get_messages($user1->id, $user2->id);
2118         // Confirm the message data is correct.
2119         $this->assertEquals(4, count($messages));
2121         $message1 = $messages[0];
2122         $message2 = $messages[1];
2123         $message3 = $messages[2];
2124         $message4 = $messages[3];
2126         $this->assertEquals($user1->id, $message1->useridfrom);
2127         $this->assertEquals($user2->id, $message1->useridto);
2128         $this->assertTrue($message1->displayblocktime);
2129         $this->assertContains('Yo!', $message1->text);
2131         $this->assertEquals($user2->id, $message2->useridfrom);
2132         $this->assertEquals($user1->id, $message2->useridto);
2133         $this->assertFalse($message2->displayblocktime);
2134         $this->assertContains('Sup mang?', $message2->text);
2136         $this->assertEquals($user1->id, $message3->useridfrom);
2137         $this->assertEquals($user2->id, $message3->useridto);
2138         $this->assertFalse($message3->displayblocktime);
2139         $this->assertContains('Writing PHPUnit tests!', $message3->text);
2141         $this->assertEquals($user2->id, $message4->useridfrom);
2142         $this->assertEquals($user1->id, $message4->useridto);
2143         $this->assertFalse($message4->displayblocktime);
2144         $this->assertContains('Word.', $message4->text);
2145     }
2147     /**
2148      * Tests retrieving conversation messages.
2149      */
2150     public function test_get_conversation_messages() {
2151         // Create some users.
2152         $user1 = self::getDataGenerator()->create_user();
2153         $user2 = self::getDataGenerator()->create_user();
2155         // Create conversation.
2156         $conversation = \core_message\api::create_conversation(
2157             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
2158             [$user1->id, $user2->id]
2159         );
2161         // The person doing the search.
2162         $this->setUser($user1);
2164         // Send some messages back and forth.
2165         $time = 1;
2166         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time + 1);
2167         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 2);
2168         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Writing PHPUnit tests!', $time + 3);
2169         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Word.', $time + 4);
2171         // Retrieve the messages.
2172         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id);
2174         // Confirm the conversation id is correct.
2175         $this->assertEquals($conversation->id, $convmessages['id']);
2177         // Confirm the message data is correct.
2178         $messages = $convmessages['messages'];
2179         $this->assertEquals(4, count($messages));
2180         $message1 = $messages[0];
2181         $message2 = $messages[1];
2182         $message3 = $messages[2];
2183         $message4 = $messages[3];
2185         $this->assertEquals($user1->id, $message1->useridfrom);
2186         $this->assertContains('Yo!', $message1->text);
2188         $this->assertEquals($user2->id, $message2->useridfrom);
2189         $this->assertContains('Sup mang?', $message2->text);
2191         $this->assertEquals($user1->id, $message3->useridfrom);
2192         $this->assertContains('Writing PHPUnit tests!', $message3->text);
2194         $this->assertEquals($user1->id, $message4->useridfrom);
2195         $this->assertContains('Word.', $message4->text);
2197         // Confirm the members data is correct.
2198         $members = $convmessages['members'];
2199         $this->assertEquals(2, count($members));
2200     }
2202     /**
2203      * Tests retrieving group conversation messages.
2204      */
2205     public function test_get_group_conversation_messages() {
2206         // Create some users.
2207         $user1 = self::getDataGenerator()->create_user();
2208         $user2 = self::getDataGenerator()->create_user();
2209         $user3 = self::getDataGenerator()->create_user();
2210         $user4 = self::getDataGenerator()->create_user();
2212         // Create group conversation.
2213         $conversation = \core_message\api::create_conversation(
2214             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2215             [$user1->id, $user2->id, $user3->id, $user4->id]
2216         );
2218         // The person doing the search.
2219         $this->setUser($user1);
2221         // Send some messages back and forth.
2222         $time = 1;
2223         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time + 1);
2224         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 2);
2225         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Writing PHPUnit tests!', $time + 3);
2226         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Word.', $time + 4);
2227         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Yeah!', $time + 5);
2229         // Retrieve the messages.
2230         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id);
2232         // Confirm the conversation id is correct.
2233         $this->assertEquals($conversation->id, $convmessages['id']);
2235         // Confirm the message data is correct.
2236         $messages = $convmessages['messages'];
2237         $this->assertEquals(5, count($messages));
2239         $message1 = $messages[0];
2240         $message2 = $messages[1];
2241         $message3 = $messages[2];
2242         $message4 = $messages[3];
2243         $message5 = $messages[4];
2245         $this->assertEquals($user1->id, $message1->useridfrom);
2246         $this->assertContains('Yo!', $message1->text);
2248         $this->assertEquals($user2->id, $message2->useridfrom);
2249         $this->assertContains('Sup mang?', $message2->text);
2251         $this->assertEquals($user3->id, $message3->useridfrom);
2252         $this->assertContains('Writing PHPUnit tests!', $message3->text);
2254         $this->assertEquals($user1->id, $message4->useridfrom);
2255         $this->assertContains('Word.', $message4->text);
2257         $this->assertEquals($user2->id, $message5->useridfrom);
2258         $this->assertContains('Yeah!', $message5->text);
2260         // Confirm the members data is correct.
2261         $members = $convmessages['members'];
2262         $this->assertEquals(3, count($members));
2263     }
2265     /**
2266      * Test verifying the sorting param for get_conversation_messages is respected().
2267      */
2268     public function test_get_conversation_messages_sorting() {
2269         // Create some users.
2270         $user1 = self::getDataGenerator()->create_user();
2271         $user2 = self::getDataGenerator()->create_user();
2272         $user3 = self::getDataGenerator()->create_user();
2274         // Create conversations - 1 group and 1 individual.
2275         $conversation = \core_message\api::create_conversation(
2276             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
2277             [$user1->id, $user2->id]
2278         );
2279         $conversation2 = \core_message\api::create_conversation(
2280             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2281             [$user1->id, $user2->id, $user3->id]
2282         );
2284         // Send some messages back and forth.
2285         $time = 1;
2286         $m1id = testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time + 1);
2287         $m2id = testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 2);
2288         $m3id = testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Writing PHPUnit tests!', $time + 3);
2289         $m4id = testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Word.', $time + 4);
2291         $gm1id = testhelper::send_fake_message_to_conversation($user1, $conversation2->id, 'Yo!', $time + 1);
2292         $gm2id = testhelper::send_fake_message_to_conversation($user2, $conversation2->id, 'Sup mang?', $time + 2);
2293         $gm3id = testhelper::send_fake_message_to_conversation($user3, $conversation2->id, 'Writing PHPUnit tests!', $time + 3);
2294         $gm4id = testhelper::send_fake_message_to_conversation($user1, $conversation2->id, 'Word.', $time + 4);
2296         // The person doing the search.
2297         $this->setUser($user1);
2299         // Retrieve the messages using default sort ('timecreated ASC') and verify ordering.
2300         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id);
2301         $messages = $convmessages['messages'];
2302         $this->assertEquals($m1id, $messages[0]->id);
2303         $this->assertEquals($m2id, $messages[1]->id);
2304         $this->assertEquals($m3id, $messages[2]->id);
2305         $this->assertEquals($m4id, $messages[3]->id);
2307         // Retrieve the messages without specifying DESC sort ordering, and verify ordering.
2308         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0, 'timecreated DESC');
2309         $messages = $convmessages['messages'];
2310         $this->assertEquals($m1id, $messages[3]->id);
2311         $this->assertEquals($m2id, $messages[2]->id);
2312         $this->assertEquals($m3id, $messages[1]->id);
2313         $this->assertEquals($m4id, $messages[0]->id);
2315         // Retrieve the messages using default sort ('timecreated ASC') and verify ordering.
2316         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation2->id);
2317         $messages = $convmessages['messages'];
2318         $this->assertEquals($gm1id, $messages[0]->id);
2319         $this->assertEquals($gm2id, $messages[1]->id);
2320         $this->assertEquals($gm3id, $messages[2]->id);
2321         $this->assertEquals($gm4id, $messages[3]->id);
2323         // Retrieve the messages without specifying DESC sort ordering, and verify ordering.
2324         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation2->id, 0, 0, 'timecreated DESC');
2325         $messages = $convmessages['messages'];
2326         $this->assertEquals($gm1id, $messages[3]->id);
2327         $this->assertEquals($gm2id, $messages[2]->id);
2328         $this->assertEquals($gm3id, $messages[1]->id);
2329         $this->assertEquals($gm4id, $messages[0]->id);
2330     }
2332     /**
2333      * Test retrieving conversation messages by providing a minimum timecreated value.
2334      */
2335     public function test_get_conversation_messages_time_from_only() {
2336         // Create some users.
2337         $user1 = self::getDataGenerator()->create_user();
2338         $user2 = self::getDataGenerator()->create_user();
2339         $user3 = self::getDataGenerator()->create_user();
2340         $user4 = self::getDataGenerator()->create_user();
2342         // Create group conversation.
2343         $conversation = \core_message\api::create_conversation(
2344             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2345             [$user1->id, $user2->id, $user3->id, $user4->id]
2346         );
2348         // The person doing the search.
2349         $this->setUser($user1);
2351         // Send some messages back and forth.
2352         $time = 1;
2353         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2354         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2355         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2356         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2358         // Retrieve the messages from $time, which should be all of them.
2359         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0, 'timecreated ASC', $time);
2361         // Confirm the conversation id is correct.
2362         $this->assertEquals($conversation->id, $convmessages['id']);
2364         // Confirm the message data is correct.
2365         $messages = $convmessages['messages'];
2366         $this->assertEquals(4, count($messages));
2368         $message1 = $messages[0];
2369         $message2 = $messages[1];
2370         $message3 = $messages[2];
2371         $message4 = $messages[3];
2373         $this->assertContains('Message 1', $message1->text);
2374         $this->assertContains('Message 2', $message2->text);
2375         $this->assertContains('Message 3', $message3->text);
2376         $this->assertContains('Message 4', $message4->text);
2378         // Confirm the members data is correct.
2379         $members = $convmessages['members'];
2380         $this->assertEquals(3, count($members));
2382         // Retrieve the messages from $time + 3, which should only be the 2 last messages.
2383         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0,
2384             'timecreated ASC', $time + 3);
2386         // Confirm the conversation id is correct.
2387         $this->assertEquals($conversation->id, $convmessages['id']);
2389         // Confirm the message data is correct.
2390         $messages = $convmessages['messages'];
2391         $this->assertEquals(2, count($messages));
2393         $message1 = $messages[0];
2394         $message2 = $messages[1];
2396         $this->assertContains('Message 3', $message1->text);
2397         $this->assertContains('Message 4', $message2->text);
2399         // Confirm the members data is correct.
2400         $members = $convmessages['members'];
2401         $this->assertEquals(2, count($members));
2402     }
2404     /**
2405      * Test retrieving conversation messages by providing a maximum timecreated value.
2406      */
2407     public function test_get_conversation_messages_time_to_only() {
2408         // Create some users.
2409         $user1 = self::getDataGenerator()->create_user();
2410         $user2 = self::getDataGenerator()->create_user();
2411         $user3 = self::getDataGenerator()->create_user();
2412         $user4 = self::getDataGenerator()->create_user();
2414         // Create group conversation.
2415         $conversation = \core_message\api::create_conversation(
2416             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2417             [$user1->id, $user2->id, $user3->id, $user4->id]
2418         );
2420         // The person doing the search.
2421         $this->setUser($user1);
2423         // Send some messages back and forth.
2424         $time = 1;
2425         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2426         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2427         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2428         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2430         // Retrieve the messages up until $time + 4, which should be all of them.
2431         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0, 'timecreated ASC',
2432             0, $time + 4);
2434         // Confirm the conversation id is correct.
2435         $this->assertEquals($conversation->id, $convmessages['id']);
2437         // Confirm the message data is correct.
2438         $messages = $convmessages['messages'];
2439         $this->assertEquals(4, count($messages));
2441         $message1 = $messages[0];
2442         $message2 = $messages[1];
2443         $message3 = $messages[2];
2444         $message4 = $messages[3];
2446         $this->assertContains('Message 1', $message1->text);
2447         $this->assertContains('Message 2', $message2->text);
2448         $this->assertContains('Message 3', $message3->text);
2449         $this->assertContains('Message 4', $message4->text);
2451         // Confirm the members data is correct.
2452         $members = $convmessages['members'];
2453         $this->assertEquals(3, count($members));
2455         // Retrieve the messages up until $time + 2, which should be the first two.
2456         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0, 'timecreated ASC',
2457             0, $time + 2);
2459         // Confirm the conversation id is correct.
2460         $this->assertEquals($conversation->id, $convmessages['id']);
2462         // Confirm the message data is correct.
2463         $messages = $convmessages['messages'];
2464         $this->assertEquals(2, count($messages));
2466         $message1 = $messages[0];
2467         $message2 = $messages[1];
2469         $this->assertContains('Message 1', $message1->text);
2470         $this->assertContains('Message 2', $message2->text);
2472         // Confirm the members data is correct.
2473         $members = $convmessages['members'];
2474         $this->assertEquals(2, count($members));
2475     }
2477     /**
2478      * Test retrieving conversation messages by providing a minimum and maximum timecreated value.
2479      */
2480     public function test_get_conversation_messages_time_from_and_to() {
2481         // Create some users.
2482         $user1 = self::getDataGenerator()->create_user();
2483         $user2 = self::getDataGenerator()->create_user();
2484         $user3 = self::getDataGenerator()->create_user();
2485         $user4 = self::getDataGenerator()->create_user();
2487         // Create group conversation.
2488         $conversation = \core_message\api::create_conversation(
2489             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2490             [$user1->id, $user2->id, $user3->id, $user4->id]
2491         );
2493         // The person doing the search.
2494         $this->setUser($user1);
2496         // Send some messages back and forth.
2497         $time = 1;
2498         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2499         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2500         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2501         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2503         // Retrieve the messages from $time + 2 up until $time + 3, which should be 2nd and 3rd message.
2504         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0,
2505             'timecreated ASC', $time + 2, $time + 3);
2507         // Confirm the conversation id is correct.
2508         $this->assertEquals($conversation->id, $convmessages['id']);
2510         // Confirm the message data is correct.
2511         $messages = $convmessages['messages'];
2512         $this->assertEquals(2, count($messages));
2514         $message1 = $messages[0];
2515         $message2 = $messages[1];
2517         $this->assertContains('Message 2', $message1->text);
2518         $this->assertContains('Message 3', $message2->text);
2520         // Confirm the members data is correct.
2521         $members = $convmessages['members'];
2522         $this->assertEquals(2, count($members));
2523     }
2526     /**
2527      * Test retrieving conversation messages by providing a limitfrom value.
2528      */
2529     public function test_get_conversation_messages_limitfrom_only() {
2530         // Create some users.
2531         $user1 = self::getDataGenerator()->create_user();
2532         $user2 = self::getDataGenerator()->create_user();
2533         $user3 = self::getDataGenerator()->create_user();
2534         $user4 = self::getDataGenerator()->create_user();
2536         // Create group conversation.
2537         $conversation = \core_message\api::create_conversation(
2538             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2539             [$user1->id, $user2->id, $user3->id, $user4->id]
2540         );
2542         // The person doing the search.
2543         $this->setUser($user1);
2545         // Send some messages back and forth.
2546         $time = 1;
2547         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2548         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2549         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2550         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2552         // Retrieve the messages from $time, which should be all of them.
2553         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 2);
2555         // Confirm the conversation id is correct.
2556         $messages = $convmessages['messages'];
2557         $this->assertEquals($conversation->id, $convmessages['id']);
2559         // Confirm the message data is correct.
2560         $this->assertEquals(2, count($messages));
2562         $message1 = $messages[0];
2563         $message2 = $messages[1];
2565         $this->assertContains('Message 3', $message1->text);
2566         $this->assertContains('Message 4', $message2->text);
2568         // Confirm the members data is correct.
2569         $members = $convmessages['members'];
2570         $this->assertEquals(2, count($members));
2571     }
2573     /**
2574      * Test retrieving conversation messages by providing a limitnum value.
2575      */
2576     public function test_get_conversation_messages_limitnum() {
2577         // Create some users.
2578         $user1 = self::getDataGenerator()->create_user();
2579         $user2 = self::getDataGenerator()->create_user();
2580         $user3 = self::getDataGenerator()->create_user();
2581         $user4 = self::getDataGenerator()->create_user();
2583         // Create group conversation.
2584         $conversation = \core_message\api::create_conversation(
2585             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2586             [$user1->id, $user2->id, $user3->id, $user4->id]
2587         );
2589         // The person doing the search.
2590         $this->setUser($user1);
2592         // Send some messages back and forth.
2593         $time = 1;
2594         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2595         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2596         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2597         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2599         // Retrieve the messages from $time, which should be all of them.
2600         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 2, 1);
2602         // Confirm the conversation id is correct.
2603         $messages = $convmessages['messages'];
2604         $this->assertEquals($conversation->id, $convmessages['id']);
2606         // Confirm the message data is correct.
2607         $messages = $convmessages['messages'];
2608         $this->assertEquals(1, count($messages));
2610         $message1 = $messages[0];
2612         $this->assertContains('Message 3', $message1->text);
2614         // Confirm the members data is correct.
2615         $members = $convmessages['members'];
2616         $this->assertEquals(1, count($members));
2617     }
2619     /**
2620      * Tests retrieving most recent message.
2621      */
2622     public function test_get_most_recent_message() {
2623         // Create some users.
2624         $user1 = self::getDataGenerator()->create_user();
2625         $user2 = self::getDataGenerator()->create_user();
2627         // The person doing the search.
2628         $this->setUser($user1);
2630         // Send some messages back and forth.
2631         $time = 1;
2632         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
2633         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
2634         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
2635         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
2637         // Retrieve the most recent messages.
2638         $message = \core_message\api::get_most_recent_message($user1->id, $user2->id);
2640         // Check the results are correct.
2641         $this->assertEquals($user2->id, $message->useridfrom);
2642         $this->assertEquals($user1->id, $message->useridto);
2643         $this->assertContains('Word.', $message->text);
2644     }
2646     /**
2647      * Tests retrieving most recent conversation message.
2648      */
2649     public function test_get_most_recent_conversation_message() {
2650         // Create some users.
2651         $user1 = self::getDataGenerator()->create_user();
2652         $user2 = self::getDataGenerator()->create_user();
2653         $user3 = self::getDataGenerator()->create_user();
2655         // Create group conversation.
2656         $conversation = \core_message\api::create_conversation(
2657             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2658             [$user1->id, $user2->id, $user3->id]
2659         );
2661         // The person getting the most recent conversation message.
2662         $this->setUser($user1);
2664         // Send some messages back and forth.
2665         $time = 1;
2666         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time + 1);
2667         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 2);
2668         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Writing PHPUnit tests!', $time + 3);
2669         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Word.', $time + 4);
2671         // Retrieve the most recent messages.
2672         $message = \core_message\api::get_most_recent_conversation_message($conversation->id, $user1->id);
2674         // Check the results are correct.
2675         $this->assertEquals($user2->id, $message->useridfrom);
2676         $this->assertContains('Word.', $message->text);
2677     }
2679     /**
2680      * Tests retrieving a user's profile.
2681      */
2682     public function test_get_profile() {
2683         // Create some users.
2684         $user1 = self::getDataGenerator()->create_user();
2686         $user2 = new stdClass();
2687         $user2->country = 'AU';
2688         $user2->city = 'Perth';
2689         $user2 = self::getDataGenerator()->create_user($user2);
2691         // The person doing the search.
2692         $this->setUser($user1);
2694         // Get the profile.
2695         $profile = \core_message\api::get_profile($user1->id, $user2->id);
2697         $this->assertEquals($user2->id, $profile->userid);
2698         $this->assertEmpty($profile->email);
2699         $this->assertEmpty($profile->country);
2700         $this->assertEmpty($profile->city);
2701         $this->assertEquals(fullname($user2), $profile->fullname);
2702         $this->assertNull($profile->isonline);
2703         $this->assertFalse($profile->isblocked);
2704         $this->assertFalse($profile->iscontact);
2705     }
2707     /**
2708      * Tests retrieving a user's profile.
2709      */
2710     public function test_get_profile_as_admin() {
2711         // The person doing the search.
2712         $this->setAdminUser();
2714         // Create some users.
2715         $user1 = self::getDataGenerator()->create_user();
2717         $user2 = new stdClass();
2718         $user2->country = 'AU';
2719         $user2->city = 'Perth';
2720         $user2 = self::getDataGenerator()->create_user($user2);
2722         // Get the profile.
2723         $profile = \core_message\api::get_profile($user1->id, $user2->id);
2725         $this->assertEquals($user2->id, $profile->userid);
2726         $this->assertEquals($user2->email, $profile->email);
2727         $this->assertEquals($user2->country, $profile->country);
2728         $this->assertEquals($user2->city, $profile->city);
2729         $this->assertEquals(fullname($user2), $profile->fullname);
2730         $this->assertFalse($profile->isonline);
2731         $this->assertFalse($profile->isblocked);
2732         $this->assertFalse($profile->iscontact);
2733     }
2735     /**
2736      * Tests checking if a user can mark all messages as read.
2737      */
2738     public function test_can_mark_all_messages_as_read() {
2739         // Set as the admin.
2740         $this->setAdminUser();
2742         // Create some users.
2743         $user1 = self::getDataGenerator()->create_user();
2744         $user2 = self::getDataGenerator()->create_user();
2745         $user3 = self::getDataGenerator()->create_user();
2747         // Send some messages back and forth.
2748         $time = 1;
2749         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
2750         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
2751         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
2752         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
2754         $conversationid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
2756         // The admin can do anything.
2757         $this->assertTrue(\core_message\api::can_mark_all_messages_as_read($user1->id, $conversationid));
2759         // Set as the user 1.
2760         $this->setUser($user1);
2762         // The user can mark the messages as he is in the conversation.
2763         $this->assertTrue(\core_message\api::can_mark_all_messages_as_read($user1->id, $conversationid));
2765         // User 1 can not mark the messages read for user 2.
2766         $this->assertFalse(\core_message\api::can_mark_all_messages_as_read($user2->id, $conversationid));
2768         // This user is not a part of the conversation.
2769         $this->assertFalse(\core_message\api::can_mark_all_messages_as_read($user3->id, $conversationid));
2770     }
2772     /**
2773      * Tests checking if a user can delete a conversation.
2774      */
2775     public function test_can_delete_conversation() {
2776         // Set as the admin.
2777         $this->setAdminUser();
2779         // Create some users.
2780         $user1 = self::getDataGenerator()->create_user();
2781         $user2 = self::getDataGenerator()->create_user();
2783         // Send some messages back and forth.
2784         $time = 1;
2785         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
2786         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
2787         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
2788         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
2790         $conversationid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
2792         // The admin can do anything.
2793         $this->assertTrue(\core_message\api::can_delete_conversation($user1->id, $conversationid));
2795         // Set as the user 1.
2796         $this->setUser($user1);
2798         // They can delete their own messages.
2799         $this->assertTrue(\core_message\api::can_delete_conversation($user1->id, $conversationid));
2801         // They can't delete someone elses.
2802         $this->assertFalse(\core_message\api::can_delete_conversation($user2->id, $conversationid));
2803     }
2805     /**
2806      * Tests deleting a conversation.
2807      */
2808     public function test_delete_conversation() {
2809         global $DB;
2811         // Create some users.
2812         $user1 = self::getDataGenerator()->create_user();
2813         $user2 = self::getDataGenerator()->create_user();
2815         // The person doing the search.
2816         $this->setUser($user1);
2818         // Send some messages back and forth.
2819         $time = 1;
2820         $m1id = $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
2821         $m2id = $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
2822         $m3id = $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
2823         $m4id = $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
2825         // Delete the conversation as user 1.
2826         \core_message\api::delete_conversation($user1->id, $user2->id);
2827         $this->assertDebuggingCalled();
2829         $muas = $DB->get_records('message_user_actions', array(), 'timecreated ASC');
2830         $this->assertCount(4, $muas);
2831         // Sort by id.
2832         ksort($muas);
2834         $mua1 = array_shift($muas);
2835         $mua2 = array_shift($muas);
2836         $mua3 = array_shift($muas);
2837         $mua4 = array_shift($muas);
2839         $this->assertEquals($user1->id, $mua1->userid);
2840         $this->assertEquals($m1id, $mua1->messageid);
2841         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua1->action);
2843         $this->assertEquals($user1->id, $mua2->userid);
2844         $this->assertEquals($m2id, $mua2->messageid);
2845         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua2->action);
2847         $this->assertEquals($user1->id, $mua3->userid);
2848         $this->assertEquals($m3id, $mua3->messageid);
2849         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua3->action);
2851         $this->assertEquals($user1->id, $mua4->userid);
2852         $this->assertEquals($m4id, $mua4->messageid);
2853         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua4->action);
2854     }
2856     /**
2857      * Tests deleting a conversation by conversation id.
2858      */
2859     public function test_delete_conversation_by_id() {
2860         global $DB;
2862         // Create some users.
2863         $user1 = self::getDataGenerator()->create_user();
2864         $user2 = self::getDataGenerator()->create_user();
2866         // The person doing the search.
2867         $this->setUser($user1);
2869         // Send some messages back and forth.
2870         $time = 1;
2871         $m1id = $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
2872         $m2id = $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
2873         $m3id = $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
2874         $m4id = $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
2876         // Delete the conversation as user 1.
2877         $conversationid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
2878         \core_message\api::delete_conversation_by_id($user1->id, $conversationid);
2880         $muas = $DB->get_records('message_user_actions', array(), 'timecreated ASC');
2881         $this->assertCount(4, $muas);
2882         // Sort by id.
2883         ksort($muas);
2885         $mua1 = array_shift($muas);
2886         $mua2 = array_shift($muas);
2887         $mua3 = array_shift($muas);
2888         $mua4 = array_shift($muas);
2890         $this->assertEquals($user1->id, $mua1->userid);
2891         $this->assertEquals($m1id, $mua1->messageid);
2892         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua1->action);
2894         $this->assertEquals($user1->id, $mua2->userid);
2895         $this->assertEquals($m2id, $mua2->messageid);
2896         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua2->action);
2898         $this->assertEquals($user1->id, $mua3->userid);
2899         $this->assertEquals($m3id, $mua3->messageid);
2900         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua3->action);
2902         $this->assertEquals($user1->id, $mua4->userid);
2903         $this->assertEquals($m4id, $mua4->messageid);
2904         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua4->action);
2905     }
2907     /**
2908      * Tests counting unread conversations.
2909      */
2910     public function test_count_unread_conversations() {
2911         $this->resetAfterTest(true);
2913         // Create some users.
2914         $user1 = self::getDataGenerator()->create_user();
2915         $user2 = self::getDataGenerator()->create_user();
2916         $user3 = self::getDataGenerator()->create_user();
2917         $user4 = self::getDataGenerator()->create_user();
2919         // The person wanting the conversation count.
2920         $this->setUser($user1);
2922         // Send some messages back and forth, have some different conversations with different users.
2923         $this->send_fake_message($user1, $user2, 'Yo!');
2924         $this->send_fake_message($user2, $user1, 'Sup mang?');
2925         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!');
2926         $this->send_fake_message($user2, $user1, 'Word.');
2928         $this->send_fake_message($user1, $user3, 'Booyah');
2929         $this->send_fake_message($user3, $user1, 'Whaaat?');
2930         $this->send_fake_message($user1, $user3, 'Nothing.');
2931         $this->send_fake_message($user3, $user1, 'Cool.');
2933         $this->send_fake_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?');
2934         $this->send_fake_message($user4, $user1, 'Yah brah, it\'s pretty rad.');
2935         $this->send_fake_message($user1, $user4, 'Dope.');
2937         // Check the amount for the current user.
2938         $this->assertEquals(3, core_message\api::count_unread_conversations());
2940         // Check the amount for the second user.
2941         $this->assertEquals(1, core_message\api::count_unread_conversations($user2));
2942     }
2944     /**
2945      * Tests deleting a conversation.
2946      */
2947     public function test_get_all_message_preferences() {
2948         $user = self::getDataGenerator()->create_user();
2949         $this->setUser($user);
2951         // Set a couple of preferences to test.
2952         set_user_preference('message_provider_mod_assign_assign_notification_loggedin', 'popup', $user);
2953         set_user_preference('message_provider_mod_assign_assign_notification_loggedoff', 'email', $user);
2955         $processors = get_message_processors();
2956         $providers = message_get_providers_for_user($user->id);
2957         $prefs = \core_message\api::get_all_message_preferences($processors, $providers, $user);
2959         $this->assertEquals(1, $prefs->mod_assign_assign_notification_loggedin['popup']);
2960         $this->assertEquals(1, $prefs->mod_assign_assign_notification_loggedoff['email']);
2961     }
2963     /**
2964      * Tests the user can post a message.
2965      */
2966     public function test_can_post_message() {
2967         // Create some users.
2968         $user1 = self::getDataGenerator()->create_user();
2969         $user2 = self::getDataGenerator()->create_user();
2971         // Set as the first user.
2972         $this->setUser($user1);
2974         // With the default privacy setting, users can't message them.
2975         $this->assertFalse(\core_message\api::can_post_message($user2));
2977         // Enrol users to the same course.
2978         $course = $this->getDataGenerator()->create_course();
2979         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
2980         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
2981         // After enrolling users to the course, they should be able to message them with the default privacy setting.
2982         $this->assertTrue(\core_message\api::can_post_message($user2));
2983     }
2985     /**
2986      * Tests the user can't post a message without proper capability.
2987      */
2988     public function test_can_post_message_without_sendmessage_cap() {
2989         global $DB;
2991         // Create some users.
2992         $user1 = self::getDataGenerator()->create_user();
2993         $user2 = self::getDataGenerator()->create_user();
2995         // Set as the user 1.
2996         $this->setUser($user1);
2998         // Remove the capability to send a message.
2999         $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
3000         unassign_capability('moodle/site:sendmessage', $roleids['user'],
3001             context_system::instance());
3003         // Check that we can not post a message without the capability.
3004         $this->assertFalse(\core_message\api::can_post_message($user2));
3005     }
3007     /**
3008      * Tests the user can post a message when they are contact.
3009      */
3010     public function test_can_post_message_when_contact() {
3011         // Create some users.
3012         $user1 = self::getDataGenerator()->create_user();
3013         $user2 = self::getDataGenerator()->create_user();
3015         // Set as the first user.
3016         $this->setUser($user1);
3018         // Check that we can not send user2 a message.
3019         $this->assertFalse(\core_message\api::can_post_message($user2));
3021         // Add users as contacts.
3022         \core_message\api::add_contact($user1->id, $user2->id);
3024         // Check that the return result is now true.
3025         $this->assertTrue(\core_message\api::can_post_message($user2));
3026     }
3028     /**
3029      * Tests the user can't post a message if they are not a contact and the user
3030      * has requested messages only from contacts.
3031      */
3032     public function test_can_post_message_when_not_contact() {
3033         // Create some users.
3034         $user1 = self::getDataGenerator()->create_user();
3035         $user2 = self::getDataGenerator()->create_user();
3037         // Set as the first user.
3038         $this->setUser($user1);
3040         // Set the second user's preference to not receive messages from non-contacts.
3041         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2->id);
3043         // Check that we can not send user 2 a message.
3044         $this->assertFalse(\core_message\api::can_post_message($user2));
3045     }
3047     /**
3048      * Tests the user can't post a message if they are blocked.
3049      */
3050     public function test_can_post_message_when_blocked() {
3051         // Create some users.
3052         $user1 = self::getDataGenerator()->create_user();
3053         $user2 = self::getDataGenerator()->create_user();
3055         // Set the user.
3056         $this->setUser($user1);
3058         // Block the second user.
3059         \core_message\api::block_user($user1->id, $user2->id);
3061         // Check that the second user can no longer send the first user a message.
3062         $this->assertFalse(\core_message\api::can_post_message($user1, $user2));
3063     }
3065     /**
3066      * Tests the user can post a message when site-wide messaging setting is enabled,
3067      * even if they are not a contact and are not members of the same course.
3068      */
3069     public function test_can_post_message_site_messaging_setting() {
3070         // Create some users.
3071         $user1 = self::getDataGenerator()->create_user();
3072         $user2 = self::getDataGenerator()->create_user();
3074         // Set as the first user.
3075         $this->setUser($user1);
3077         // By default, user only can be messaged by contacts and members of any of his/her courses.
3078         $this->assertFalse(\core_message\api::can_post_message($user2));
3080         // Enable site-wide messagging privacy setting. The user will be able to receive messages from everybody.
3081         set_config('messagingallusers', true);
3083         // Set the second user's preference to receive messages from everybody.
3084         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_SITE, $user2->id);
3086         // Check that we can send user2 a message.
3087         $this->assertTrue(\core_message\api::can_post_message($user2));
3089         // Disable site-wide messagging privacy setting. The user will be able to receive messages from contacts
3090         // and members sharing a course with her.
3091         set_config('messagingallusers', false);
3093         // As site-wide messaging setting is disabled, the value for user2 will be changed to MESSAGE_PRIVACY_COURSEMEMBER.
3094         $this->assertFalse(\core_message\api::can_post_message($user2));
3096         // Enrol users to the same course.
3097         $course = $this->getDataGenerator()->create_course();
3098         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3099         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3100         // Check that we can send user2 a message because they are sharing a course.
3101         $this->assertTrue(\core_message\api::can_post_message($user2));
3103         // Set the second user's preference to receive messages only from contacts.
3104         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2->id);
3105         // Check that now the user2 can't be contacted because user1 is not their contact.
3106         $this->assertFalse(\core_message\api::can_post_message($user2));
3108         // Make contacts user1 and user2.
3109         \core_message\api::add_contact($user2->id, $user1->id);
3110         // Check that we can send user2 a message because they are contacts.
3111         $this->assertTrue(\core_message\api::can_post_message($user2));
3112     }
3114     /**
3115      * Tests the user with the messageanyuser capability can post a message.
3116      */
3117     public function test_can_post_message_with_messageanyuser_cap() {
3118         global $DB;
3120         // Create some users.
3121         $teacher1 = self::getDataGenerator()->create_user();
3122         $student1 = self::getDataGenerator()->create_user();
3123         $student2 = self::getDataGenerator()->create_user();
3125         // Create users not enrolled in any course.
3126         $user1 = self::getDataGenerator()->create_user();
3128         // Create a course.
3129         $course1 = $this->getDataGenerator()->create_course();
3131         // Enrol the users in the course.
3132         $this->getDataGenerator()->enrol_user($teacher1->id, $course1->id, 'editingteacher');
3133         $this->getDataGenerator()->enrol_user($student1->id, $course1->id, 'student');
3134         $this->getDataGenerator()->enrol_user($student2->id, $course1->id, 'student');
3136         // Set some student preferences to not receive messages from non-contacts.
3137         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $student1->id);
3139         // Check that we can send student1 a message because teacher has the messageanyuser cap by default.
3140         $this->assertTrue(\core_message\api::can_post_message($student1, $teacher1));
3141         // Check that the teacher can't contact user1 because it's not his teacher.
3142         $this->assertFalse(\core_message\api::can_post_message($user1, $teacher1));
3144         // Remove the messageanyuser capability from the course1 for teachers.
3145         $coursecontext = context_course::instance($course1->id);
3146         $teacherrole = $DB->get_record('role', ['shortname' => 'editingteacher']);
3147         assign_capability('moodle/site:messageanyuser', CAP_PROHIBIT, $teacherrole->id, $coursecontext->id);
3148         $coursecontext->mark_dirty();
3150         // Check that we can't send user1 a message because they are not contacts.
3151         $this->assertFalse(\core_message\api::can_post_message($student1, $teacher1));
3152         // However, teacher can message student2 because they are sharing a course.
3153         $this->assertTrue(\core_message\api::can_post_message($student2, $teacher1));
3154     }
3156     /**
3157      * Verify the expected behaviour of the can_send_message_to_conversation() method for authenticated users with default settings.
3158      */
3159     public function test_can_send_message_to_conversation_basic() {
3160         // Create some users.
3161         $user1 = self::getDataGenerator()->create_user();
3162         $user2 = self::getDataGenerator()->create_user();
3163         $user3 = self::getDataGenerator()->create_user();
3165         // Create an individual conversation between user1 and user2.
3166         $ic1 = \core_message\api::create_conversation(
3167             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3168             [
3169                 $user1->id,
3170                 $user2->id
3171             ]
3172         );
3174         // Create a group conversation between and users 1, 2 and 3.
3175         $gc1 = \core_message\api::create_conversation(
3176             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3177             [
3178                 $user1->id,
3179                 $user2->id,
3180                 $user3->id
3181             ]
3182         );
3184         // For group conversations, there are no user privacy checks, so only membership in the conversation is needed.
3185         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3187         // For individual conversations, the default privacy setting of 'only contacts and course members' applies.
3188         // Users are not in the same course, nor are they contacts, so messages cannot be sent.
3189         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3191         // Enrol the users into the same course.
3192         $course = $this->getDataGenerator()->create_course();
3193         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3194         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3196         // After enrolling users to the course, they should be able to message them with the default privacy setting.
3197         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3198     }
3200     /**
3201      * Verify the behaviour of can_send_message_to_conversation() for authenticated users without the sendmessage capability.
3202      */
3203     public function test_can_send_message_to_conversation_sendmessage_cap() {
3204         global $DB;
3206         $user1 = self::getDataGenerator()->create_user();
3207         $user2 = self::getDataGenerator()->create_user();
3208         $user3 = self::getDataGenerator()->create_user();
3210         // Enrol the users into the same course.
3211         $course = $this->getDataGenerator()->create_course();
3212         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3213         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3214         $this->getDataGenerator()->enrol_user($user3->id, $course->id);
3216         // Create an individual conversation between user1 and user2.
3217         $ic1 = \core_message\api::create_conversation(
3218             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3219             [
3220                 $user1->id,
3221                 $user2->id
3222             ]
3223         );
3225         // Group conversation between and users 1, 2 and 3.
3226         $gc1 = \core_message\api::create_conversation(
3227             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3228             [
3229                 $user1->id,
3230                 $user2->id,
3231                 $user3->id
3232             ]
3233         );
3235         // Default settings - user1 can send a message to both conversations.
3236         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3237         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3239         // Remove the capability to send a message.
3240         $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
3241         unassign_capability('moodle/site:sendmessage', $roleids['user'], context_system::instance());
3243         // Verify that a user cannot send a message to either an individual or a group conversation.
3244         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3245         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3246     }
3248     /**
3249      * Verify the behaviour of can_send_message_to_conversation() for authenticated users without the messageanyuser capability.
3250      */
3251     public function test_can_send_message_to_conversation_messageanyuser_cap() {
3252         global $DB;
3254         $user1 = self::getDataGenerator()->create_user();
3255         $user2 = self::getDataGenerator()->create_user();
3256         $user3 = self::getDataGenerator()->create_user();
3258         // Enrol the users into the same course.
3259         $course = $this->getDataGenerator()->create_course();
3260         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3261         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3262         $this->getDataGenerator()->enrol_user($user3->id, $course->id);
3264         // Create an individual conversation between user1 and user2.
3265         $ic1 = \core_message\api::create_conversation(
3266             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3267             [
3268                 $user1->id,
3269                 $user2->id
3270             ]
3271         );
3273         // Group conversation between and users 1, 2 and 3.
3274         $gc1 = \core_message\api::create_conversation(
3275             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3276             [
3277                 $user1->id,
3278                 $user2->id,
3279                 $user3->id
3280             ]
3281         );
3283         // Update the message preference for user2, so they can only be messaged by contacts.
3284         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2->id);
3286         // Verify that the user cannot be contacted in the individual conversation and that groups are unaffected.
3287         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3288         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3290         // Assign the 'messageanyuser' capability to user1 at system context.