a94c6ca71cb520d74b571397fe7da5cb87da792a
[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         global $DB;
318         $this->resetAfterTest();
320         // Create some users.
321         $users = [];
322         foreach (range(1, 8) as $i) {
323             $user = new stdClass();
324             $user->firstname = ($i == 4) ? 'User' : 'User search'; // Ensure the fourth user won't match the search term.
325             $user->lastname = $i;
326             $user = $this->getDataGenerator()->create_user($user);
327             $users[$i] = $user;
328         }
330         // Enrol a few users in the same course, but leave them as non-contacts.
331         $course1 = $this->getDataGenerator()->create_course();
332         $course2 = $this->getDataGenerator()->create_course();
334         $this->setAdminUser();
335         $this->getDataGenerator()->enrol_user($users[1]->id, $course1->id);
336         $this->getDataGenerator()->enrol_user($users[6]->id, $course1->id);
337         $this->getDataGenerator()->enrol_user($users[7]->id, $course1->id);
339         // Add some other users as contacts.
340         \core_message\api::add_contact($users[1]->id, $users[2]->id);
341         \core_message\api::add_contact($users[3]->id, $users[1]->id);
342         \core_message\api::add_contact($users[1]->id, $users[4]->id);
344         // Enrol a user as a teacher in the course, and make the teacher role a course contact role.
345         $this->getDataGenerator()->enrol_user($users[8]->id, $course2->id, 'editingteacher');
346         $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
347         set_config('coursecontact', $teacherrole->id);
349         // Create individual conversations between some users, one contact and one non-contact.
350         $ic1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
351             [$users[1]->id, $users[2]->id]);
352         $ic2 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
353             [$users[6]->id, $users[1]->id]);
355         // Create a group conversation between 4 users, including a contact and a non-contact.
356         $gc1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
357             [$users[1]->id, $users[2]->id, $users[4]->id, $users[7]->id], 'Project chat');
359         // Set as the user performing the search.
360         $this->setUser($users[1]);
362         // Perform a search with $CFG->messagingallusers disabled.
363         set_config('messagingallusers', 0);
364         $result = \core_message\api::message_search_users($users[1]->id, 'search');
366         // Confirm that we returns contacts and non-contacts.
367         $this->assertArrayHasKey(0, $result);
368         $this->assertArrayHasKey(1, $result);
369         $contacts = $result[0];
370         $noncontacts = $result[1];
372         // Check that we retrieved the correct contacts.
373         $this->assertCount(2, $contacts);
374         $this->assertEquals($users[2]->id, $contacts[0]->id);
375         $this->assertEquals($users[3]->id, $contacts[1]->id);
377         // Verify the correct conversations were returned for the contacts.
378         $this->assertCount(2, $contacts[0]->conversations);
379         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $contacts[0]->conversations[$gc1->id]->type);
380         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $contacts[0]->conversations[$ic1->id]->type);
382         $this->assertCount(0, $contacts[1]->conversations);
384         // Check that we retrieved the correct non-contacts.
385         // When site wide messaging is disabled, we expect to see only those users who we share a course with and whose profiles
386         // are visible in that course. This excludes users like course contacts.
387         $this->assertCount(2, $noncontacts);
388         $this->assertEquals($users[6]->id, $noncontacts[0]->id);
389         $this->assertEquals($users[7]->id, $noncontacts[1]->id);
391         // Verify the correct conversations were returned for the non-contacts.
392         $this->assertCount(1, $noncontacts[0]->conversations);
393         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
394             $noncontacts[0]->conversations[$ic2->id]->type);
396         $this->assertCount(1, $noncontacts[1]->conversations);
397         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $noncontacts[1]->conversations[$gc1->id]->type);
398     }
400     /**
401      * Tests searching for users when site-wide messaging is enabled.
402      *
403      * This test verifies that any contacts are returned, as well as any non-contacts,
404      * provided the searching user can view their profile.
405      */
406     public function test_message_search_users_messagingallusers_enabled() {
407         global $DB;
408         $this->resetAfterTest();
410         // Create some users.
411         $users = [];
412         foreach (range(1, 9) as $i) {
413             $user = new stdClass();
414             $user->firstname = ($i == 4) ? 'User' : 'User search'; // Ensure the fourth user won't match the search term.
415             $user->lastname = $i;
416             $user = $this->getDataGenerator()->create_user($user);
417             $users[$i] = $user;
418         }
420         $course1 = $this->getDataGenerator()->create_course();
421         $coursecontext = \context_course::instance($course1->id);
423         // Enrol a few users in the same course, but leave them as non-contacts.
424         $this->setAdminUser();
425         $this->getDataGenerator()->enrol_user($users[1]->id, $course1->id, 'student');
426         $this->getDataGenerator()->enrol_user($users[6]->id, $course1->id, 'student');
427         $this->getDataGenerator()->enrol_user($users[7]->id, $course1->id, 'student');
429         // Add some other users as contacts.
430         \core_message\api::add_contact($users[1]->id, $users[2]->id);
431         \core_message\api::add_contact($users[3]->id, $users[1]->id);
432         \core_message\api::add_contact($users[1]->id, $users[4]->id);
434         // Enrol a user as a teacher in the course, and make the teacher role a course contact role.
435         $this->getDataGenerator()->enrol_user($users[9]->id, $course1->id, 'editingteacher');
436         $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
437         set_config('coursecontact', $teacherrole->id);
439         // Create individual conversations between some users, one contact and one non-contact.
440         $ic1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
441             [$users[1]->id, $users[2]->id]);
442         $ic2 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
443             [$users[6]->id, $users[1]->id]);
445         // Create a group conversation between 5 users, including a contact and a non-contact, and a user NOT in a shared course.
446         $gc1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
447             [$users[1]->id, $users[2]->id, $users[4]->id, $users[7]->id, $users[8]->id], 'Project chat');
449         // Set as the user performing the search.
450         $this->setUser($users[1]);
452         // Perform a search with $CFG->messagingallusers enabled.
453         set_config('messagingallusers', 1);
454         $result = \core_message\api::message_search_users($users[1]->id, 'search');
456         // Confirm that we returns contacts and non-contacts.
457         $this->assertArrayHasKey(0, $result);
458         $this->assertArrayHasKey(1, $result);
459         $contacts = $result[0];
460         $noncontacts = $result[1];
462         // Check that we retrieved the correct contacts.
463         $this->assertCount(2, $contacts);
464         $this->assertEquals($users[2]->id, $contacts[0]->id);
465         $this->assertEquals($users[3]->id, $contacts[1]->id);
467         // Verify the correct conversations were returned for the contacts.
468         $this->assertCount(2, $contacts[0]->conversations);
469         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $contacts[0]->conversations[$gc1->id]->type);
470         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $contacts[0]->conversations[$ic1->id]->type);
472         $this->assertCount(0, $contacts[1]->conversations);
474         // Check that we retrieved the correct non-contacts.
475         // If site wide messaging is enabled, we expect to only be able to search for users whose profiles we can view.
476         // In this case, as a student, that's the course contact for course2 and those noncontacts sharing a course with user1.
477         $this->assertCount(3, $noncontacts);
478         $this->assertEquals($users[6]->id, $noncontacts[0]->id);
479         $this->assertEquals($users[7]->id, $noncontacts[1]->id);
480         $this->assertEquals($users[9]->id, $noncontacts[2]->id);
481         $this->assertCount(1, $noncontacts[0]->conversations);
482         $this->assertCount(1, $noncontacts[1]->conversations);
483         $this->assertCount(0, $noncontacts[2]->conversations);
484     }
486     /**
487      * Verify searching for users find themselves when they have self-conversations.
488      */
489     public function test_message_search_users_self_conversations() {
490         $this->resetAfterTest();
492         // Create some users.
493         $user1 = new stdClass();
494         $user1->firstname = 'User';
495         $user1->lastname = 'One';
496         $user1 = $this->getDataGenerator()->create_user($user1);
497         $user2 = new stdClass();
498         $user2->firstname = 'User';
499         $user2->lastname = 'Two';
500         $user2 = $this->getDataGenerator()->create_user($user2);
502         // Create self-conversation for user1.
503         $sc1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_SELF, [$user1->id]);
504         testhelper::send_fake_message_to_conversation($user1, $sc1->id, 'Hi myself!');
506         // Perform a search as user1.
507         $this->setUser($user1);
508         $result = \core_message\api::message_search_users($user1->id, 'One');
510         // Check user1 is found as non-contacts.
511         $this->assertCount(0, $result[0]);
512         $this->assertCount(1, $result[1]);
513     }
515     /**
516      * Verify searching for users works even if no matching users from either contacts, or non-contacts can be found.
517      */
518     public function test_message_search_users_with_empty_result() {
519         $this->resetAfterTest();
521         // Create some users, but make sure neither will match the search term.
522         $user1 = new stdClass();
523         $user1->firstname = 'User';
524         $user1->lastname = 'One';
525         $user1 = $this->getDataGenerator()->create_user($user1);
526         $user2 = new stdClass();
527         $user2->firstname = 'User';
528         $user2->lastname = 'Two';
529         $user2 = $this->getDataGenerator()->create_user($user2);
531         // Perform a search as user1.
532         $this->setUser($user1);
533         $result = \core_message\api::message_search_users($user1->id, 'search');
535         // Check results are empty.
536         $this->assertCount(0, $result[0]);
537         $this->assertCount(0, $result[1]);
538     }
540     /**
541      * Test verifying that limits and offsets work for both the contacts and non-contacts return data.
542      */
543     public function test_message_search_users_limit_offset() {
544         $this->resetAfterTest();
546         // Create 20 users.
547         $users = [];
548         foreach (range(1, 20) as $i) {
549             $user = new stdClass();
550             $user->firstname = "User search";
551             $user->lastname = $i;
552             $user = $this->getDataGenerator()->create_user($user);
553             $users[$i] = $user;
554         }
556         // Enrol the first 9 users in the same course, but leave them as non-contacts.
557         $this->setAdminUser();
558         $course1 = $this->getDataGenerator()->create_course();
559         foreach (range(1, 9) as $i) {
560             $this->getDataGenerator()->enrol_user($users[$i]->id, $course1->id);
561         }
563         // Add 5 users, starting at the 11th user, as contacts for user1.
564         foreach (range(11, 15) as $i) {
565             \core_message\api::add_contact($users[1]->id, $users[$i]->id);
566         }
568         // Set as the user performing the search.
569         $this->setUser($users[1]);
571         // Search using a limit of 3.
572         // This tests the case where we have more results than the limit for both contacts and non-contacts.
573         $result = \core_message\api::message_search_users($users[1]->id, 'search', 0, 3);
574         $contacts = $result[0];
575         $noncontacts = $result[1];
577         // Check that we retrieved the correct contacts.
578         $this->assertCount(3, $contacts);
579         $this->assertEquals($users[11]->id, $contacts[0]->id);
580         $this->assertEquals($users[12]->id, $contacts[1]->id);
581         $this->assertEquals($users[13]->id, $contacts[2]->id);
583         // Check that we retrieved the correct non-contacts.
584         $this->assertCount(3, $noncontacts);
585         $this->assertEquals($users[2]->id, $noncontacts[0]->id);
586         $this->assertEquals($users[3]->id, $noncontacts[1]->id);
587         $this->assertEquals($users[4]->id, $noncontacts[2]->id);
589         // Now, offset to get the next batch of results.
590         // We expect to see 2 contacts, and 3 non-contacts.
591         $result = \core_message\api::message_search_users($users[1]->id, 'search', 3, 3);
592         $contacts = $result[0];
593         $noncontacts = $result[1];
594         $this->assertCount(2, $contacts);
595         $this->assertEquals($users[14]->id, $contacts[0]->id);
596         $this->assertEquals($users[15]->id, $contacts[1]->id);
598         $this->assertCount(3, $noncontacts);
599         $this->assertEquals($users[5]->id, $noncontacts[0]->id);
600         $this->assertEquals($users[6]->id, $noncontacts[1]->id);
601         $this->assertEquals($users[7]->id, $noncontacts[2]->id);
603         // Now, offset to get the next batch of results.
604         // We expect to see 0 contacts, and 2 non-contacts.
605         $result = \core_message\api::message_search_users($users[1]->id, 'search', 6, 3);
606         $contacts = $result[0];
607         $noncontacts = $result[1];
608         $this->assertCount(0, $contacts);
610         $this->assertCount(2, $noncontacts);
611         $this->assertEquals($users[8]->id, $noncontacts[0]->id);
612         $this->assertEquals($users[9]->id, $noncontacts[1]->id);
613     }
615     /**
616      * Tests searching users as a user having the 'moodle/user:viewdetails' capability.
617      */
618     public function test_message_search_users_with_cap() {
619         $this->resetAfterTest();
620         global $DB;
622         // Create some users.
623         $users = [];
624         foreach (range(1, 8) as $i) {
625             $user = new stdClass();
626             $user->firstname = ($i == 4) ? 'User' : 'User search'; // Ensure the fourth user won't match the search term.
627             $user->lastname = $i;
628             $user = $this->getDataGenerator()->create_user($user);
629             $users[$i] = $user;
630         }
632         // Enrol a few users in the same course, but leave them as non-contacts.
633         $course1 = $this->getDataGenerator()->create_course();
634         $this->setAdminUser();
635         $this->getDataGenerator()->enrol_user($users[1]->id, $course1->id);
636         $this->getDataGenerator()->enrol_user($users[6]->id, $course1->id);
637         $this->getDataGenerator()->enrol_user($users[7]->id, $course1->id);
639         // Add some other users as contacts.
640         \core_message\api::add_contact($users[1]->id, $users[2]->id);
641         \core_message\api::add_contact($users[3]->id, $users[1]->id);
642         \core_message\api::add_contact($users[1]->id, $users[4]->id);
644         // Set as the user performing the search.
645         $this->setUser($users[1]);
647         // Grant the authenticated user role the capability 'user:viewdetails' at site context.
648         $authenticatedrole = $DB->get_record('role', ['shortname' => 'user'], '*', MUST_EXIST);
649         assign_capability('moodle/user:viewdetails', CAP_ALLOW, $authenticatedrole->id, context_system::instance());
651         // Perform a search with $CFG->messagingallusers disabled.
652         set_config('messagingallusers', 0);
653         $result = \core_message\api::message_search_users($users[1]->id, 'search');
654         $contacts = $result[0];
655         $noncontacts = $result[1];
657         // Check that we retrieved the correct contacts.
658         $this->assertCount(2, $contacts);
659         $this->assertEquals($users[2]->id, $contacts[0]->id);
660         $this->assertEquals($users[3]->id, $contacts[1]->id);
662         // Check that we retrieved the correct non-contacts.
663         // Site-wide messaging is disabled, so we expect to be able to search for any users whose profiles we can view.
664         $this->assertCount(2, $noncontacts);
665         $this->assertEquals($users[6]->id, $noncontacts[0]->id);
666         $this->assertEquals($users[7]->id, $noncontacts[1]->id);
667     }
669     /**
670      * Tests searching users with messaging disabled.
671      */
672     public function test_message_search_users_messaging_disabled() {
673         $this->resetAfterTest();
675         // Create a user.
676         $user = $this->getDataGenerator()->create_user();
678         // Disable messaging.
679         set_config('messaging', 0);
681         // Ensure an exception is thrown.
682         $this->expectException('moodle_exception');
683         \core_message\api::message_search_users($user->id, 'User');
684     }
686     /**
687      * Tests getting conversations between 2 users.
688      */
689     public function test_get_conversations_between_users() {
690         // Create some users.
691         $user1 = new stdClass();
692         $user1->firstname = 'User';
693         $user1->lastname = 'One';
694         $user1 = self::getDataGenerator()->create_user($user1);
696         $user2 = new stdClass();
697         $user2->firstname = 'User';
698         $user2->lastname = 'Two';
699         $user2 = self::getDataGenerator()->create_user($user2);
701         $user3 = new stdClass();
702         $user3->firstname = 'User search';
703         $user3->lastname = 'Three';
704         $user3 = self::getDataGenerator()->create_user($user3);
706         $user4 = new stdClass();
707         $user4->firstname = 'User';
708         $user4->lastname = 'Four';
709         $user4 = self::getDataGenerator()->create_user($user4);
711         $user5 = new stdClass();
712         $user5->firstname = 'User';
713         $user5->lastname = 'Five';
714         $user5 = self::getDataGenerator()->create_user($user5);
716         $user6 = new stdClass();
717         $user6->firstname = 'User search';
718         $user6->lastname = 'Six';
719         $user6 = self::getDataGenerator()->create_user($user6);
721         // Add some users as contacts.
722         \core_message\api::add_contact($user1->id, $user2->id);
723         \core_message\api::add_contact($user6->id, $user1->id);
725         // Create private conversations with some users.
726         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
727             array($user1->id, $user2->id));
728         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
729             array($user3->id, $user1->id));
731         // Create a group conversation with users.
732         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
733             array($user1->id, $user2->id, $user3->id, $user4->id),
734             'Project chat');
736         // Check that we retrieved the correct conversations.
737         $this->assertCount(2, \core_message\api::get_conversations_between_users($user1->id, $user2->id));
738         $this->assertCount(2, \core_message\api::get_conversations_between_users($user2->id, $user1->id));
739         $this->assertCount(2, \core_message\api::get_conversations_between_users($user1->id, $user3->id));
740         $this->assertCount(2, \core_message\api::get_conversations_between_users($user3->id, $user1->id));
741         $this->assertCount(1, \core_message\api::get_conversations_between_users($user1->id, $user4->id));
742         $this->assertCount(1, \core_message\api::get_conversations_between_users($user4->id, $user1->id));
743         $this->assertCount(0, \core_message\api::get_conversations_between_users($user1->id, $user5->id));
744         $this->assertCount(0, \core_message\api::get_conversations_between_users($user5->id, $user1->id));
745         $this->assertCount(0, \core_message\api::get_conversations_between_users($user1->id, $user6->id));
746         $this->assertCount(0, \core_message\api::get_conversations_between_users($user6->id, $user1->id));
747     }
749     /**
750      * Tests getting self-conversations.
751      */
752     public function test_get_self_conversation() {
753         // Create some users.
754         $user1 = new stdClass();
755         $user1->firstname = 'User';
756         $user1->lastname = 'One';
757         $user1 = self::getDataGenerator()->create_user($user1);
759         $user2 = new stdClass();
760         $user2->firstname = 'User';
761         $user2->lastname = 'Two';
762         $user2 = self::getDataGenerator()->create_user($user2);
764         $user3 = new stdClass();
765         $user3->firstname = 'User search';
766         $user3->lastname = 'Three';
767         $user3 = self::getDataGenerator()->create_user($user3);
769         // Add some users as contacts.
770         \core_message\api::add_contact($user1->id, $user2->id);
771         \core_message\api::add_contact($user3->id, $user1->id);
773         // Create private conversations with some users.
774         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
775             array($user1->id, $user2->id));
776         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
777             array($user3->id, $user1->id));
779         // Create a group conversation with users.
780         $gc = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
781             array($user1->id, $user2->id, $user3->id),
782             'Project chat');
784         // Create self-conversations.
785         $sc1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_SELF,
786             array($user1->id));
787         $sc2 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_SELF,
788             array($user2->id));
790         // Send message to self-conversation.
791         testhelper::send_fake_message_to_conversation($user1, $sc1->id, 'Message to myself!');
793         $rsc1 = \core_message\api::get_self_conversation($user1->id);
794         $rsc2 = \core_message\api::get_self_conversation($user2->id);
795         $rsc3 = \core_message\api::get_self_conversation($user3->id);
797         // Check that we retrieved the correct conversations.
798         $this->assertEquals($sc1->id, $rsc1->id);
799         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_SELF, $sc1->type);
800         $this->assertEquals($sc2->id, $rsc2->id);
801         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_SELF, $sc2->type);
802         $this->assertFalse($rsc3);
803     }
805     /**
806      * Tests searching messages.
807      */
808     public function test_search_messages() {
809         $this->resetAfterTest();
811         // Create some users.
812         $user1 = self::getDataGenerator()->create_user();
813         $user2 = self::getDataGenerator()->create_user();
814         $user3 = self::getDataGenerator()->create_user();
816         // The person doing the search.
817         $this->setUser($user1);
819         // Create self-conversation.
820         $sc = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_SELF, [$user1->id]);
822         // Create group conversation.
823         $gc = \core_message\api::create_conversation(
824             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
825             [$user1->id, $user2->id, $user3->id]
826         );
828         // Send some messages back and forth.
829         $time = 1;
830         testhelper::send_fake_message_to_conversation($user1, $sc->id, 'Test message to self!', $time);
831         testhelper::send_fake_message_to_conversation($user1, $gc->id, 'My hero!', $time + 1);
832         $this->send_fake_message($user3, $user1, 'Don\'t block me.', 0, $time + 2);
833         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 3);
834         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 4);
835         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 5);
836         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 6);
838         $convid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
839         $conv2id = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]);
841         // Block user 3.
842         \core_message\api::block_user($user1->id, $user3->id);
844         // Perform a search.
845         $messages = \core_message\api::search_messages($user1->id, 'o');
847         // Confirm the data is correct.
848         $this->assertEquals(5, count($messages));
849         $message1 = $messages[0];
850         $message2 = $messages[1];
851         $message3 = $messages[2];
852         $message4 = $messages[3];
853         $message5 = $messages[4];
855         $this->assertEquals($user2->id, $message1->userid);
856         $this->assertEquals($user2->id, $message1->useridfrom);
857         $this->assertEquals(fullname($user2), $message1->fullname);
858         $this->assertTrue($message1->ismessaging);
859         $this->assertEquals('Word.', $message1->lastmessage);
860         $this->assertNotEmpty($message1->messageid);
861         $this->assertNull($message1->isonline);
862         $this->assertFalse($message1->isread);
863         $this->assertFalse($message1->isblocked);
864         $this->assertNull($message1->unreadcount);
865         $this->assertEquals($convid, $message1->conversationid);
867         $this->assertEquals($user2->id, $message2->userid);
868         $this->assertEquals($user1->id, $message2->useridfrom);
869         $this->assertEquals(fullname($user2), $message2->fullname);
870         $this->assertTrue($message2->ismessaging);
871         $this->assertEquals('Yo!', $message2->lastmessage);
872         $this->assertNotEmpty($message2->messageid);
873         $this->assertNull($message2->isonline);
874         $this->assertTrue($message2->isread);
875         $this->assertFalse($message2->isblocked);
876         $this->assertNull($message2->unreadcount);
877         $this->assertEquals($convid, $message2->conversationid);
879         $this->assertEquals($user3->id, $message3->userid);
880         $this->assertEquals($user3->id, $message3->useridfrom);
881         $this->assertEquals(fullname($user3), $message3->fullname);
882         $this->assertTrue($message3->ismessaging);
883         $this->assertEquals('Don\'t block me.', $message3->lastmessage);
884         $this->assertNotEmpty($message3->messageid);
885         $this->assertNull($message3->isonline);
886         $this->assertFalse($message3->isread);
887         $this->assertTrue($message3->isblocked);
888         $this->assertNull($message3->unreadcount);
889         $this->assertEquals($conv2id, $message3->conversationid);
891         // This is a group conversation. For now, search_messages returns only one of the other users on the conversation. It can't
892         // be guaranteed who will be returned in the first place, so we need to use the in_array to check all the possibilities.
893         $this->assertTrue(in_array($message4->userid, [$user2->id, $user3->id]));
894         $this->assertEquals($user1->id, $message4->useridfrom);
895         $this->assertTrue($message4->ismessaging);
896         $this->assertEquals('My hero!', $message4->lastmessage);
897         $this->assertNotEmpty($message4->messageid);
898         $this->assertNull($message4->isonline);
899         $this->assertTrue($message4->isread);
900         $this->assertNull($message4->unreadcount);
901         $this->assertEquals($gc->id, $message4->conversationid);
903         $this->assertEquals($user1->id, $message5->userid);
904         $this->assertEquals($user1->id, $message5->useridfrom);
905         $this->assertEquals(fullname($user1), $message5->fullname);
906         $this->assertTrue($message5->ismessaging);
907         $this->assertEquals('Test message to self!', $message5->lastmessage);
908         $this->assertNotEmpty($message5->messageid);
909         $this->assertFalse($message5->isonline);
910         $this->assertTrue($message5->isread);
911         $this->assertFalse($message5->isblocked);
912         $this->assertNull($message5->unreadcount);
913         $this->assertEquals($sc->id, $message5->conversationid);
914     }
916     /**
917      * Test verifying that favourited conversations can be retrieved.
918      */
919     public function test_get_favourite_conversations() {
920         // Create some users.
921         $user1 = self::getDataGenerator()->create_user();
922         $user2 = self::getDataGenerator()->create_user();
923         $user3 = self::getDataGenerator()->create_user();
924         $user4 = self::getDataGenerator()->create_user();
926         // The person doing the search.
927         $this->setUser($user1);
929         // No conversations yet.
930         $this->assertEquals([], \core_message\api::get_conversations($user1->id));
932         // Create some conversations for user1.
933         $time = 1;
934         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
935         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
936         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
937         $messageid1 = $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
939         $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
940         $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
941         $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
942         $messageid2 = $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
944         $this->send_fake_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?', 0, $time + 9);
945         $this->send_fake_message($user4, $user1, 'Yah brah, it\'s pretty rad.', 0, $time + 10);
946         $messageid3 = $this->send_fake_message($user1, $user4, 'Dope.', 0, $time + 11);
948         // Favourite the first 2 conversations for user1.
949         $convoids = [];
950         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
951         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]);
952         $user1context = context_user::instance($user1->id);
953         $service = \core_favourites\service_factory::get_service_for_user_context($user1context);
954         foreach ($convoids as $convoid) {
955             $service->create_favourite('core_message', 'message_conversations', $convoid, $user1context);
956         }
958         // We should have 3 conversations.
959         $this->assertCount(3, \core_message\api::get_conversations($user1->id));
961         // And 2 favourited conversations.
962         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, true);
963         $this->assertCount(2, $conversations);
964     }
966     /**
967      * Tests retrieving favourite conversations with a limit and offset to ensure pagination works correctly.
968      */
969     public function test_get_favourite_conversations_limit_offset() {
970         // Create some users.
971         $user1 = self::getDataGenerator()->create_user();
972         $user2 = self::getDataGenerator()->create_user();
973         $user3 = self::getDataGenerator()->create_user();
974         $user4 = self::getDataGenerator()->create_user();
976         // The person doing the search.
977         $this->setUser($user1);
979         // No conversations yet.
980         $this->assertEquals([], \core_message\api::get_conversations($user1->id));
982         // Create some conversations for user1.
983         $time = 1;
984         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
985         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
986         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
987         $messageid1 = $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
989         $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
990         $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
991         $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
992         $messageid2 = $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
994         $this->send_fake_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?', 0, $time + 9);
995         $this->send_fake_message($user4, $user1, 'Yah brah, it\'s pretty rad.', 0, $time + 10);
996         $messageid3 = $this->send_fake_message($user1, $user4, 'Dope.', 0, $time + 11);
998         // Favourite the all conversations for user1.
999         $convoids = [];
1000         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
1001         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]);
1002         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user4->id]);
1003         $user1context = context_user::instance($user1->id);
1004         $service = \core_favourites\service_factory::get_service_for_user_context($user1context);
1005         foreach ($convoids as $convoid) {
1006             $service->create_favourite('core_message', 'message_conversations', $convoid, $user1context);
1007         }
1009         // Get all records, using offset 0 and large limit.
1010         $this->assertCount(2, \core_message\api::get_conversations($user1->id, 1, 10, null, true));
1012         // Now, get 10 conversations starting at the second record. We should see 2 conversations.
1013         $this->assertCount(2, \core_message\api::get_conversations($user1->id, 1, 10, null, true));
1015         // Now, try to get favourited conversations using an invalid offset.
1016         $this->assertCount(0, \core_message\api::get_conversations($user1->id, 4, 10, null, true));
1017     }
1019     /**
1020      * Tests retrieving favourite conversations when a conversation contains a deleted user.
1021      */
1022     public function test_get_favourite_conversations_with_deleted_user() {
1023         // Create some users.
1024         $user1 = self::getDataGenerator()->create_user();
1025         $user2 = self::getDataGenerator()->create_user();
1026         $user3 = self::getDataGenerator()->create_user();
1028         // Send some messages back and forth, have some different conversations with different users.
1029         $time = 1;
1030         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
1031         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
1032         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
1033         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
1035         $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
1036         $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
1037         $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
1038         $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
1040         // Favourite the all conversations for user1.
1041         $convoids = [];
1042         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
1043         $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]);
1044         $user1context = context_user::instance($user1->id);
1045         $service = \core_favourites\service_factory::get_service_for_user_context($user1context);
1046         foreach ($convoids as $convoid) {
1047             $service->create_favourite('core_message', 'message_conversations', $convoid, $user1context);
1048         }
1050         // Delete the second user.
1051         delete_user($user2);
1053         // Retrieve the conversations.
1054         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, true);
1056         // We should have both conversations, despite the other user being soft-deleted.
1057         $this->assertCount(2, $conversations);
1059         // Confirm the conversation is from the non-deleted user.
1060         $conversation = reset($conversations);
1061         $this->assertEquals($convoids[1], $conversation->id);
1062     }
1064     /**
1065      * Test confirming that conversations can be marked as favourites.
1066      */
1067     public function test_set_favourite_conversation() {
1068         // Create some users.
1069         $user1 = self::getDataGenerator()->create_user();
1070         $user2 = self::getDataGenerator()->create_user();
1071         $user3 = self::getDataGenerator()->create_user();
1073         // Send some messages back and forth, have some different conversations with different users.
1074         $time = 1;
1075         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
1076         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
1077         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
1078         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
1080         $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
1081         $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
1082         $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
1083         $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
1085         // Favourite the first conversation as user 1.
1086         $conversationid1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
1087         $favourite = \core_message\api::set_favourite_conversation($conversationid1, $user1->id);
1089         // Verify we have a single favourite conversation a user 1.
1090         $this->assertCount(1, \core_message\api::get_conversations($user1->id, 0, 20, null, true));
1092         // Verify we have no favourites as user2, despite being a member in that conversation.
1093         $this->assertCount(0, \core_message\api::get_conversations($user2->id, 0, 20, null, true));
1095         // Try to favourite the same conversation again should just return the existing favourite.
1096         $repeatresult = \core_message\api::set_favourite_conversation($conversationid1, $user1->id);
1097         $this->assertEquals($favourite->id, $repeatresult->id);
1098     }
1100     /**
1101      * Test verifying that trying to mark a non-existent conversation as a favourite, results in an exception.
1102      */
1103     public function test_set_favourite_conversation_nonexistent_conversation() {
1104         // Create some users.
1105         $user1 = self::getDataGenerator()->create_user();
1106         // Try to favourite a non-existent conversation.
1107         $this->expectException(\moodle_exception::class);
1108         \core_message\api::set_favourite_conversation(0, $user1->id);
1109     }
1111     /**
1112      * Test verifying that a conversation cannot be marked as favourite unless the user is a member of that conversation.
1113      */
1114     public function test_set_favourite_conversation_non_member() {
1115         // Create some users.
1116         $user1 = self::getDataGenerator()->create_user();
1117         $user2 = self::getDataGenerator()->create_user();
1118         $user3 = self::getDataGenerator()->create_user();
1120         // Send some messages back and forth, have some different conversations with different users.
1121         $time = 1;
1122         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
1123         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
1124         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
1125         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
1127         $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
1128         $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
1129         $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
1130         $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
1132         // Try to favourite the first conversation as user 3, who is not a member.
1133         $conversationid1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
1134         $this->expectException(\moodle_exception::class);
1135         \core_message\api::set_favourite_conversation($conversationid1, $user3->id);
1136     }
1138     /**
1139      * Test confirming that those conversations marked as favourites can be unfavourited.
1140      */
1141     public function test_unset_favourite_conversation() {
1142         // Create some users.
1143         $user1 = self::getDataGenerator()->create_user();
1144         $user2 = self::getDataGenerator()->create_user();
1145         $user3 = self::getDataGenerator()->create_user();
1147         // Send some messages back and forth, have some different conversations with different users.
1148         $time = 1;
1149         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
1150         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
1151         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
1152         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
1154         $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
1155         $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
1156         $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
1157         $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
1159         // Favourite the first conversation as user 1 and the second as user 3.
1160         $conversationid1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
1161         $conversationid2 = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]);
1162         \core_message\api::set_favourite_conversation($conversationid1, $user1->id);
1163         \core_message\api::set_favourite_conversation($conversationid2, $user3->id);
1165         // Verify we have a single favourite conversation for both user 1 and user 3.
1166         $this->assertCount(1, \core_message\api::get_conversations($user1->id, 0, 20, null, true));
1167         $this->assertCount(1, \core_message\api::get_conversations($user3->id, 0, 20, null, true));
1169         // Now unfavourite the conversation as user 1.
1170         \core_message\api::unset_favourite_conversation($conversationid1, $user1->id);
1172         // Verify we have a single favourite conversation user 3 only, and none for user1.
1173         $this->assertCount(1, \core_message\api::get_conversations($user3->id, 0, 20, null, true));
1174         $this->assertCount(0, \core_message\api::get_conversations($user1->id, 0, 20, null, true));
1176         // Try to favourite the same conversation again as user 1.
1177         $this->expectException(\moodle_exception::class);
1178         \core_message\api::unset_favourite_conversation($conversationid1, $user1->id);
1179     }
1181     /**
1182      * Test verifying that a valid conversation cannot be unset as a favourite if it's not marked as a favourite.
1183      */
1184     public function test_unset_favourite_conversation_not_favourite() {
1185         // Create some users.
1186         $user1 = self::getDataGenerator()->create_user();
1187         $user2 = self::getDataGenerator()->create_user();
1189         // Send some messages back and forth, have some different conversations with different users.
1190         $time = 1;
1191         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
1192         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
1193         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
1194         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
1196         // Now try to unfavourite the conversation as user 1.
1197         $conversationid1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
1198         $this->expectException(\moodle_exception::class);
1199         \core_message\api::unset_favourite_conversation($conversationid1, $user1->id);
1200     }
1202     /**
1203      * Test verifying that a non-existent conversation cannot be unset as a favourite.
1204      */
1205     public function test_unset_favourite_conversation_non_existent_conversation() {
1206         // Create some users.
1207         $user1 = self::getDataGenerator()->create_user();
1209         // Now try to unfavourite the conversation as user 1.
1210         $this->expectException(\moodle_exception::class);
1211         \core_message\api::unset_favourite_conversation(0, $user1->id);
1212     }
1214     /**
1215      * Helper to seed the database with initial state.
1216      */
1217     protected function create_conversation_test_data() {
1218         // Create some users.
1219         $user1 = self::getDataGenerator()->create_user();
1220         $user2 = self::getDataGenerator()->create_user();
1221         $user3 = self::getDataGenerator()->create_user();
1222         $user4 = self::getDataGenerator()->create_user();
1224         $time = 1;
1226         // Create some conversations. We want:
1227         // 1) At least one of each type (group, individual) of which user1 IS a member and DID send the most recent message.
1228         // 2) At least one of each type (group, individual) of which user1 IS a member and DID NOT send the most recent message.
1229         // 3) At least one of each type (group, individual) of which user1 IS NOT a member.
1230         // 4) At least two group conversation having 0 messages, of which user1 IS a member (To confirm conversationid ordering).
1231         // 5) At least one group conversation having 0 messages, of which user1 IS NOT a member.
1233         // Individual conversation, user1 is a member, last message from other user.
1234         $ic1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1235             [$user1->id, $user2->id]);
1236         testhelper::send_fake_message_to_conversation($user1, $ic1->id, 'Message 1', $time);
1237         testhelper::send_fake_message_to_conversation($user2, $ic1->id, 'Message 2', $time + 1);
1239         // Individual conversation, user1 is a member, last message from user1.
1240         $ic2 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1241             [$user1->id, $user3->id]);
1242         testhelper::send_fake_message_to_conversation($user3, $ic2->id, 'Message 3', $time + 2);
1243         testhelper::send_fake_message_to_conversation($user1, $ic2->id, 'Message 4', $time + 3);
1245         // Individual conversation, user1 is not a member.
1246         $ic3 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1247             [$user2->id, $user3->id]);
1248         testhelper::send_fake_message_to_conversation($user2, $ic3->id, 'Message 5', $time + 4);
1249         testhelper::send_fake_message_to_conversation($user3, $ic3->id, 'Message 6', $time + 5);
1251         // Group conversation, user1 is not a member.
1252         $gc1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1253             [$user2->id, $user3->id, $user4->id], 'Project discussions');
1254         testhelper::send_fake_message_to_conversation($user2, $gc1->id, 'Message 7', $time + 6);
1255         testhelper::send_fake_message_to_conversation($user4, $gc1->id, 'Message 8', $time + 7);
1257         // Group conversation, user1 is a member, last message from another user.
1258         $gc2 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1259             [$user1->id, $user3->id, $user4->id], 'Group chat');
1260         testhelper::send_fake_message_to_conversation($user1, $gc2->id, 'Message 9', $time + 8);
1261         testhelper::send_fake_message_to_conversation($user3, $gc2->id, 'Message 10', $time + 9);
1262         testhelper::send_fake_message_to_conversation($user4, $gc2->id, 'Message 11', $time + 10);
1264         // Group conversation, user1 is a member, last message from user1.
1265         $gc3 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1266             [$user1->id, $user2->id, $user3->id, $user4->id], 'Group chat again!');
1267         testhelper::send_fake_message_to_conversation($user4, $gc3->id, 'Message 12', $time + 11);
1268         testhelper::send_fake_message_to_conversation($user3, $gc3->id, 'Message 13', $time + 12);
1269         testhelper::send_fake_message_to_conversation($user1, $gc3->id, 'Message 14', $time + 13);
1271         // Empty group conversations (x2), user1 is a member.
1272         $gc4 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1273             [$user1->id, $user2->id, $user3->id], 'Empty group');
1274         $gc5 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1275             [$user1->id, $user2->id, $user4->id], 'Another empty group');
1277         // Empty group conversation, user1 is NOT a member.
1278         $gc6 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1279             [$user2->id, $user3->id, $user4->id], 'Empty group 3');
1281         return [$user1, $user2, $user3, $user4, $ic1, $ic2, $ic3, $gc1, $gc2, $gc3, $gc4, $gc5, $gc6];
1282     }
1284     /**
1285      * Test verifying get_conversations when no limits, offsets, type filters or favourite restrictions are used.
1286      */
1287     public function test_get_conversations_no_restrictions() {
1288         global $DB;
1289         // No conversations should exist yet.
1290         $user1 = self::getDataGenerator()->create_user();
1291         $this->assertEquals([], \core_message\api::get_conversations($user1->id));
1293         // Get a bunch of conversations, some group, some individual and in different states.
1294         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1295             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1297         // Get all conversations for user1.
1298         $conversations = core_message\api::get_conversations($user1->id);
1300         // Verify there are 2 individual conversation, 2 group conversations, and 2 empty group conversations.
1301         // The conversations with the most recent messages should be listed first, followed by the empty
1302         // conversations, with the most recently created first.
1303         $this->assertCount(6, $conversations);
1304         $typecounts  = array_count_values(array_column($conversations, 'type'));
1305         $this->assertEquals(2, $typecounts[1]);
1306         $this->assertEquals(4, $typecounts[2]);
1308         // Those conversations having messages should be listed first, ordered by most recent message time.
1309         $this->assertEquals($gc3->id, $conversations[0]->id);
1310         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $conversations[0]->type);
1311         $this->assertFalse($conversations[0]->isfavourite);
1312         $this->assertCount(1, $conversations[0]->members);
1313         $this->assertEquals(4, $conversations[0]->membercount);
1314         $this->assertCount(1, $conversations[0]->messages);
1315         $message = $DB->get_record('messages', ['id' => $conversations[0]->messages[0]->id]);
1316         $expectedmessagetext = message_format_message_text($message);
1317         $this->assertEquals($expectedmessagetext, $conversations[0]->messages[0]->text);
1318         $this->assertEquals($user1->id, $conversations[0]->messages[0]->useridfrom);
1320         $this->assertEquals($gc2->id, $conversations[1]->id);
1321         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $conversations[1]->type);
1322         $this->assertFalse($conversations[1]->isfavourite);
1323         $this->assertCount(1, $conversations[1]->members);
1324         $this->assertEquals(3, $conversations[1]->membercount);
1325         $this->assertCount(1, $conversations[1]->messages);
1326         $message = $DB->get_record('messages', ['id' => $conversations[1]->messages[0]->id]);
1327         $expectedmessagetext = message_format_message_text($message);
1328         $this->assertEquals($expectedmessagetext, $conversations[1]->messages[0]->text);
1329         $this->assertEquals($user4->id, $conversations[1]->messages[0]->useridfrom);
1331         $this->assertEquals($ic2->id, $conversations[2]->id);
1332         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $conversations[2]->type);
1333         $this->assertFalse($conversations[2]->isfavourite);
1334         $this->assertCount(1, $conversations[2]->members);
1335         $this->assertEquals($user3->id, $conversations[2]->members[$user3->id]->id);
1336         $this->assertEquals(2, $conversations[2]->membercount);
1337         $this->assertCount(1, $conversations[2]->messages);
1338         $message = $DB->get_record('messages', ['id' => $conversations[2]->messages[0]->id]);
1339         $expectedmessagetext = message_format_message_text($message);
1340         $this->assertEquals($expectedmessagetext, $conversations[2]->messages[0]->text);
1341         $this->assertEquals($user1->id, $conversations[2]->messages[0]->useridfrom);
1343         $this->assertEquals($ic1->id, $conversations[3]->id);
1344         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $conversations[3]->type);
1345         $this->assertFalse($conversations[3]->isfavourite);
1346         $this->assertCount(1, $conversations[3]->members);
1347         $this->assertEquals(2, $conversations[3]->membercount);
1348         $this->assertCount(1, $conversations[3]->messages);
1349         $message = $DB->get_record('messages', ['id' => $conversations[3]->messages[0]->id]);
1350         $expectedmessagetext = message_format_message_text($message);
1351         $this->assertEquals($expectedmessagetext, $conversations[3]->messages[0]->text);
1352         $this->assertEquals($user2->id, $conversations[3]->messages[0]->useridfrom);
1354         // Of the groups without messages, we expect to see the most recently created first.
1355         $this->assertEquals($gc5->id, $conversations[4]->id);
1356         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $conversations[4]->type);
1357         $this->assertFalse($conversations[4]->isfavourite);
1358         $this->assertCount(0, $conversations[4]->members); // No members returned, because no recent messages exist.
1359         $this->assertEquals(3, $conversations[4]->membercount);
1360         $this->assertEmpty($conversations[4]->messages);
1362         $this->assertEquals($gc4->id, $conversations[5]->id);
1363         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $conversations[5]->type);
1364         $this->assertFalse($conversations[5]->isfavourite);
1365         $this->assertCount(0, $conversations[5]->members);
1366         $this->assertEquals(3, $conversations[5]->membercount);
1367         $this->assertEmpty($conversations[5]->messages);
1369         // Verify format of the return structure.
1370         foreach ($conversations as $conv) {
1371             $this->assertObjectHasAttribute('id', $conv);
1372             $this->assertObjectHasAttribute('name', $conv);
1373             $this->assertObjectHasAttribute('subname', $conv);
1374             $this->assertObjectHasAttribute('imageurl', $conv);
1375             $this->assertObjectHasAttribute('type', $conv);
1376             $this->assertObjectHasAttribute('isfavourite', $conv);
1377             $this->assertObjectHasAttribute('membercount', $conv);
1378             $this->assertObjectHasAttribute('isread', $conv);
1379             $this->assertObjectHasAttribute('unreadcount', $conv);
1380             $this->assertObjectHasAttribute('members', $conv);
1381             foreach ($conv->members as $member) {
1382                 $this->assertObjectHasAttribute('id', $member);
1383                 $this->assertObjectHasAttribute('fullname', $member);
1384                 $this->assertObjectHasAttribute('profileimageurl', $member);
1385                 $this->assertObjectHasAttribute('profileimageurlsmall', $member);
1386                 $this->assertObjectHasAttribute('isonline', $member);
1387                 $this->assertObjectHasAttribute('showonlinestatus', $member);
1388                 $this->assertObjectHasAttribute('isblocked', $member);
1389                 $this->assertObjectHasAttribute('iscontact', $member);
1390                 $this->assertObjectHasAttribute('isdeleted', $member);
1391                 $this->assertObjectHasAttribute('canmessage', $member);
1392                 $this->assertObjectHasAttribute('requirescontact', $member);
1393                 $this->assertObjectHasAttribute('contactrequests', $member);
1394             }
1395             $this->assertObjectHasAttribute('messages', $conv);
1396             foreach ($conv->messages as $message) {
1397                 $this->assertObjectHasAttribute('id', $message);
1398                 $this->assertObjectHasAttribute('useridfrom', $message);
1399                 $this->assertObjectHasAttribute('text', $message);
1400                 $this->assertObjectHasAttribute('timecreated', $message);
1401             }
1402         }
1403     }
1405     /**
1406      * Test verifying that html format messages are supported, and that message_format_message_text() is being called appropriately.
1407      */
1408     public function test_get_conversations_message_format() {
1409         global $DB;
1410         // Create some users.
1411         $user1 = self::getDataGenerator()->create_user();
1412         $user2 = self::getDataGenerator()->create_user();
1414         // Create conversation.
1415         $conversation = \core_message\api::create_conversation(
1416             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1417             [$user1->id, $user2->id]
1418         );
1420         // Send some messages back and forth.
1421         $time = 1;
1422         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 1);
1423         $mid = testhelper::send_fake_message_to_conversation($user1, $conversation->id, '<a href="#">A link</a>', $time + 2);
1425         // Verify the format of the html message.
1426         $message = $DB->get_record('messages', ['id' => $mid]);
1427         $expectedmessagetext = message_format_message_text($message);
1428         $conversations = \core_message\api::get_conversations($user1->id);
1429         $messages = $conversations[0]->messages;
1430         $this->assertEquals($expectedmessagetext, $messages[0]->text);
1431     }
1433     /**
1434      * Test verifying get_conversations identifies if a conversation is muted or not.
1435      */
1436     public function test_get_conversations_some_muted() {
1437         // Create some users.
1438         $user1 = self::getDataGenerator()->create_user();
1439         $user2 = self::getDataGenerator()->create_user();
1440         $user3 = self::getDataGenerator()->create_user();
1442         $conversation1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1443             [$user1->id, $user2->id]);
1444         testhelper::send_fake_message_to_conversation($user1, $conversation1->id, 'Message 1');
1445         testhelper::send_fake_message_to_conversation($user2, $conversation1->id, 'Message 2');
1446         \core_message\api::mute_conversation($user1->id, $conversation1->id);
1448         $conversation2 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1449             [$user1->id, $user3->id]);
1450         testhelper::send_fake_message_to_conversation($user1, $conversation2->id, 'Message 1');
1451         testhelper::send_fake_message_to_conversation($user2, $conversation2->id, 'Message 2');
1453         $conversation3 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1454             [$user1->id, $user2->id]);
1455         \core_message\api::mute_conversation($user1->id, $conversation3->id);
1457         $conversation4 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1458             [$user1->id, $user3->id]);
1460         $conversations = \core_message\api::get_conversations($user1->id);
1462         usort($conversations, function($first, $second){
1463             return $first->id > $second->id;
1464         });
1466         $conv1 = array_shift($conversations);
1467         $conv2 = array_shift($conversations);
1468         $conv3 = array_shift($conversations);
1469         $conv4 = array_shift($conversations);
1471         $this->assertTrue($conv1->ismuted);
1472         $this->assertFalse($conv2->ismuted);
1473         $this->assertTrue($conv3->ismuted);
1474         $this->assertFalse($conv4->ismuted);
1475     }
1477     /**
1478      * Tests retrieving conversations with a limit and offset to ensure pagination works correctly.
1479      */
1480     public function test_get_conversations_limit_offset() {
1481         // Get a bunch of conversations, some group, some individual and in different states.
1482         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1483             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1485         // Get all conversations for user1, limited to 1 result.
1486         $conversations = core_message\api::get_conversations($user1->id, 0, 1);
1488         // Verify the first conversation.
1489         $this->assertCount(1, $conversations);
1490         $conversation = array_shift($conversations);
1491         $this->assertEquals($conversation->id, $gc3->id);
1493         // Verify the next conversation.
1494         $conversations = \core_message\api::get_conversations($user1->id, 1, 1);
1495         $this->assertCount(1, $conversations);
1496         $this->assertEquals($gc2->id, $conversations[0]->id);
1498         // Verify the next conversation.
1499         $conversations = \core_message\api::get_conversations($user1->id, 2, 1);
1500         $this->assertCount(1, $conversations);
1501         $this->assertEquals($ic2->id, $conversations[0]->id);
1503         // Skip one and get both empty conversations.
1504         $conversations = \core_message\api::get_conversations($user1->id, 4, 2);
1505         $this->assertCount(2, $conversations);
1506         $this->assertEquals($gc5->id, $conversations[0]->id);
1507         $this->assertEmpty($conversations[0]->messages);
1508         $this->assertEquals($gc4->id, $conversations[1]->id);
1509         $this->assertEmpty($conversations[1]->messages);
1511         // Ask for an offset that doesn't exist and verify no conversations are returned.
1512         $conversations = \core_message\api::get_conversations($user1->id, 10, 1);
1513         $this->assertCount(0, $conversations);
1514     }
1516     /**
1517      * Test verifying the type filtering behaviour of the
1518      */
1519     public function test_get_conversations_type_filter() {
1520         // Get a bunch of conversations, some group, some individual and in different states.
1521         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1522             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1524         // Verify we can ask for only individual conversations.
1525         $conversations = \core_message\api::get_conversations($user1->id, 0, 20,
1526             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL);
1527         $this->assertCount(2, $conversations);
1529         // Verify we can ask for only group conversations.
1530         $conversations = \core_message\api::get_conversations($user1->id, 0, 20,
1531             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP);
1532         $this->assertCount(4, $conversations);
1534         // Verify an exception is thrown if an unrecognized type is specified.
1535         $this->expectException(\moodle_exception::class);
1536         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, 0);
1537     }
1539     /**
1540      * Tests retrieving conversations when a 'self' conversation exists.
1541      */
1542     public function test_get_conversations_self_conversations() {
1543         global $DB;
1545         // Create a conversation between one user and themself.
1546         $user1 = self::getDataGenerator()->create_user();
1547         $user2 = self::getDataGenerator()->create_user();
1548         $user3 = self::getDataGenerator()->create_user();
1549         $user4 = self::getDataGenerator()->create_user();
1551         // Create some individual conversations.
1552         $ic1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1553             [$user1->id, $user2->id]);
1554         $ic2 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1555             [$user1->id, $user3->id]);
1556         testhelper::send_fake_message_to_conversation($user1, $ic1->id, 'Message from user1 to user2');
1558         // Create some self-conversations.
1559         $sc1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_SELF, [$user1->id]);
1560         $sc4 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_SELF, [$user4->id]);
1561         testhelper::send_fake_message_to_conversation($user1, $sc1->id, 'Test message to self 1!');
1563         // Verify we are in a 'self' conversation state.
1564         $members = $DB->get_records('message_conversation_members', ['conversationid' => $sc1->id]);
1565         $this->assertCount(1, $members);
1566         $member = array_pop($members);
1567         $this->assertEquals($user1->id, $member->userid);
1569         // Verify the self-conversations are returned by the method.
1570         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF);
1571         $this->assertCount(1, $conversations);
1572         $conversation = array_pop($conversations);
1573         $this->assertEquals($conversation->id, $sc1->id);
1575         $conversations = \core_message\api::get_conversations($user4->id);
1576         // The self-conversation.
1577         $this->assertCount(1, $conversations);
1579         // Get only private conversations for user1 (empty conversations, like $ic2, are not returned).
1580         $conversations = \core_message\api::get_conversations($user1->id, 0, 20,
1581             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL);
1582         $this->assertCount(1, $conversations);
1584         // Merge self with private conversations for user1.
1585         $conversations = \core_message\api::get_conversations($user1->id, 0, 20,
1586             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, null, true);
1587         $this->assertCount(2, $conversations);
1589         // Get only private conversations for user2.
1590         $conversations = \core_message\api::get_conversations($user2->id, 0, 20,
1591             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL);
1592         $this->assertCount(1, $conversations);
1594         // Merge self with private conversations for user2 (is the same result than before because user2 hasn't self-conversations).
1595         $conversations = \core_message\api::get_conversations($user2->id, 0, 20,
1596             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, null, true);
1597         $this->assertCount(1, $conversations);
1598     }
1600     /**
1601      * Tests retrieving conversations when a conversation contains a deleted user.
1602      */
1603     public function test_get_conversations_with_deleted_user() {
1604         // Get a bunch of conversations, some group, some individual and in different states.
1605         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1606             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1608         // Delete the second user and retrieve the conversations.
1609         // We should have 6 still, as conversations with soft-deleted users are still returned.
1610         // Group conversations are also present, albeit with less members.
1611         delete_user($user2);
1612         // This is to confirm an exception is not thrown when a user AND the user context is deleted.
1613         // We no longer delete the user context, but historically we did.
1614         context_helper::delete_instance(CONTEXT_USER, $user2->id);
1615         $conversations = \core_message\api::get_conversations($user1->id);
1616         $this->assertCount(6, $conversations);
1617         $this->assertEquals($gc3->id, $conversations[0]->id);
1618         $this->assertcount(1, $conversations[0]->members);
1619         $this->assertEquals($gc2->id, $conversations[1]->id);
1620         $this->assertcount(1, $conversations[1]->members);
1621         $this->assertEquals($ic2->id, $conversations[2]->id);
1622         $this->assertEquals($ic1->id, $conversations[3]->id);
1623         $this->assertEquals($gc5->id, $conversations[4]->id);
1624         $this->assertEquals($gc4->id, $conversations[5]->id);
1626         // Delete a user from a group conversation where that user had sent the most recent message.
1627         // This user will still be present in the members array, as will the message in the messages array.
1628         delete_user($user4);
1629         $conversations = \core_message\api::get_conversations($user1->id);
1630         $this->assertCount(6, $conversations);
1631         $this->assertEquals($gc2->id, $conversations[1]->id);
1632         $this->assertcount(1, $conversations[1]->members);
1633         $this->assertEquals($user4->id, $conversations[1]->members[$user4->id]->id);
1634         $this->assertcount(1, $conversations[1]->messages);
1635         $this->assertEquals($user4->id, $conversations[1]->messages[0]->useridfrom);
1637         // Delete the third user and retrieve the conversations.
1638         // We should have 6 still, as conversations with soft-deleted users are still returned.
1639         // Group conversations are also present, albeit with less members.
1640         delete_user($user3);
1641         $conversations = \core_message\api::get_conversations($user1->id);
1642         $this->assertCount(6, $conversations);
1643         $this->assertEquals($gc3->id, $conversations[0]->id);
1644         $this->assertcount(1, $conversations[0]->members);
1645         $this->assertEquals($gc2->id, $conversations[1]->id);
1646         $this->assertcount(1, $conversations[1]->members);
1647         $this->assertEquals($ic2->id, $conversations[2]->id);
1648         $this->assertEquals($ic1->id, $conversations[3]->id);
1649         $this->assertEquals($gc5->id, $conversations[4]->id);
1650         $this->assertEquals($gc4->id, $conversations[5]->id);
1651     }
1653     /**
1654      * Test confirming the behaviour of get_conversations() when users delete all messages.
1655      */
1656     public function test_get_conversations_deleted_messages() {
1657         // Get a bunch of conversations, some group, some individual and in different states.
1658         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1659             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1661         $conversations = \core_message\api::get_conversations($user1->id);
1662         $this->assertCount(6, $conversations);
1664         // Delete all messages from a group conversation the user is in - it should be returned.
1665         $this->assertTrue(\core_message\api::is_user_in_conversation($user1->id, $gc2->id));
1666         $convmessages = \core_message\api::get_conversation_messages($user1->id, $gc2->id);
1667         $messages = $convmessages['messages'];
1668         foreach ($messages as $message) {
1669             \core_message\api::delete_message($user1->id, $message->id);
1670         }
1671         $conversations = \core_message\api::get_conversations($user1->id);
1672         $this->assertCount(6, $conversations);
1673         $this->assertContains($gc2->id, array_column($conversations, 'id'));
1675         // Delete all messages from an individual conversation the user is in - it should not be returned.
1676         $this->assertTrue(\core_message\api::is_user_in_conversation($user1->id, $ic1->id));
1677         $convmessages = \core_message\api::get_conversation_messages($user1->id, $ic1->id);
1678         $messages = $convmessages['messages'];
1679         foreach ($messages as $message) {
1680             \core_message\api::delete_message($user1->id, $message->id);
1681         }
1682         $conversations = \core_message\api::get_conversations($user1->id);
1683         $this->assertCount(5, $conversations);
1684         $this->assertNotContains($ic1->id, array_column($conversations, 'id'));
1685     }
1687     /**
1688      * Test verifying the behaviour of get_conversations() when fetching favourite conversations with only a single
1689      * favourite.
1690      */
1691     public function test_get_conversations_favourite_conversations_single() {
1692         // Get a bunch of conversations, some group, some individual and in different states.
1693         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1694             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1696         // Mark a single conversation as favourites.
1697         \core_message\api::set_favourite_conversation($ic2->id, $user1->id);
1699         // Get the conversation, first with no restrictions, confirming the favourite status of the conversations.
1700         $conversations = \core_message\api::get_conversations($user1->id);
1701         $this->assertCount(6, $conversations);
1702         foreach ($conversations as $conv) {
1703             if (in_array($conv->id, [$ic2->id])) {
1704                 $this->assertTrue($conv->isfavourite);
1705             } else {
1706                 $this->assertFalse($conv->isfavourite);
1707             }
1708         }
1710         // Now, get ONLY favourite conversations.
1711         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, true);
1712         $this->assertCount(1, $conversations);
1713         foreach ($conversations as $conv) {
1714             $this->assertTrue($conv->isfavourite);
1715             $this->assertEquals($ic2->id, $conv->id);
1716         }
1718         // Now, try ONLY favourites of type 'group'.
1719         $conversations = \core_message\api::get_conversations($user1->id, 0, 20,
1720             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, true);
1721         $this->assertEmpty($conversations);
1723         // And NO favourite conversations.
1724         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, false);
1725         $this->assertCount(5, $conversations);
1726         foreach ($conversations as $conv) {
1727             $this->assertFalse($conv->isfavourite);
1728             $this->assertNotEquals($ic2, $conv->id);
1729         }
1730     }
1732     /**
1733      * Test verifying the behaviour of get_conversations() when fetching favourite conversations.
1734      */
1735     public function test_get_conversations_favourite_conversations() {
1736         // Get a bunch of conversations, some group, some individual and in different states.
1737         list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1738             $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1740         // Try to get ONLY favourite conversations, when no favourites exist.
1741         $this->assertEquals([], \core_message\api::get_conversations($user1->id, 0, 20, null, true));
1743         // Try to get NO favourite conversations, when no favourites exist.
1744         $this->assertCount(6, \core_message\api::get_conversations($user1->id, 0, 20, null, false));
1746         // Mark a few conversations as favourites.
1747         \core_message\api::set_favourite_conversation($ic1->id, $user1->id);
1748         \core_message\api::set_favourite_conversation($gc2->id, $user1->id);
1749         \core_message\api::set_favourite_conversation($gc5->id, $user1->id);
1750         $favouriteids = [$ic1->id, $gc2->id, $gc5->id];
1752         // Get the conversations, first with no restrictions, confirming the favourite status of the conversations.
1753         $conversations = \core_message\api::get_conversations($user1->id);
1754         $this->assertCount(6, $conversations);
1755         foreach ($conversations as $conv) {
1756             if (in_array($conv->id, $favouriteids)) {
1757                 $this->assertTrue($conv->isfavourite);
1758             } else {
1759                 $this->assertFalse($conv->isfavourite);
1760             }
1761         }
1763         // Now, get ONLY favourite conversations.
1764         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, true);
1765         $this->assertCount(3, $conversations);
1766         foreach ($conversations as $conv) {
1767             $this->assertTrue($conv->isfavourite);
1768             $this->assertNotFalse(array_search($conv->id, $favouriteids));
1769         }
1771         // Now, try ONLY favourites of type 'group'.
1772         $conversations = \core_message\api::get_conversations($user1->id, 0, 20,
1773             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, true);
1774         $this->assertCount(2, $conversations);
1775         foreach ($conversations as $conv) {
1776             $this->assertTrue($conv->isfavourite);
1777             $this->assertNotFalse(array_search($conv->id, [$gc2->id, $gc5->id]));
1778         }
1780         // And NO favourite conversations.
1781         $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, false);
1782         $this->assertCount(3, $conversations);
1783         foreach ($conversations as $conv) {
1784             $this->assertFalse($conv->isfavourite);
1785             $this->assertFalse(array_search($conv->id, $favouriteids));
1786         }
1787     }
1789     /**
1790      * Test verifying get_conversations when there are users in a group and/or individual conversation. The reason this
1791      * test is performed is because we do not need as much data for group conversations (saving DB calls), so we want
1792      * to confirm this happens.
1793      */
1794     public function test_get_conversations_user_in_group_and_individual_chat() {
1795         $this->resetAfterTest();
1797         $user1 = self::getDataGenerator()->create_user();
1798         $user2 = self::getDataGenerator()->create_user();
1799         $user3 = self::getDataGenerator()->create_user();
1801         $conversation = \core_message\api::create_conversation(
1802             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1803             [
1804                 $user1->id,
1805                 $user2->id
1806             ],
1807             'Individual conversation'
1808         );
1810         testhelper::send_fake_message_to_conversation($user1, $conversation->id);
1812         $conversation = \core_message\api::create_conversation(
1813             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
1814             [
1815                 $user1->id,
1816                 $user2->id,
1817             ],
1818             'Group conversation'
1819         );
1821         testhelper::send_fake_message_to_conversation($user1, $conversation->id);
1823         \core_message\api::create_contact_request($user1->id, $user2->id);
1824         \core_message\api::create_contact_request($user1->id, $user3->id);
1826         $conversations = \core_message\api::get_conversations($user2->id);
1828         $groupconversation = array_shift($conversations);
1829         $individualconversation = array_shift($conversations);
1831         $this->assertEquals('Group conversation', $groupconversation->name);
1832         $this->assertEquals('Individual conversation', $individualconversation->name);
1834         $this->assertCount(1, $groupconversation->members);
1835         $this->assertCount(1, $individualconversation->members);
1837         $groupmember = reset($groupconversation->members);
1838         $this->assertNull($groupmember->requirescontact);
1839         $this->assertNull($groupmember->canmessage);
1840         $this->assertEmpty($groupmember->contactrequests);
1842         $individualmember = reset($individualconversation->members);
1843         $this->assertNotNull($individualmember->requirescontact);
1844         $this->assertNotNull($individualmember->canmessage);
1845         $this->assertNotEmpty($individualmember->contactrequests);
1846     }
1848     /**
1849      * Test verifying that group linked conversations are returned and contain a subname matching the course name.
1850      */
1851     public function test_get_conversations_group_linked() {
1852         global $CFG, $DB;
1854         // Create some users.
1855         $user1 = self::getDataGenerator()->create_user();
1856         $user2 = self::getDataGenerator()->create_user();
1857         $user3 = self::getDataGenerator()->create_user();
1859         $course1 = $this->getDataGenerator()->create_course();
1861         // Create a group with a linked conversation and a valid image.
1862         $this->setAdminUser();
1863         $this->getDataGenerator()->enrol_user($user1->id, $course1->id);
1864         $this->getDataGenerator()->enrol_user($user2->id, $course1->id);
1865         $this->getDataGenerator()->enrol_user($user3->id, $course1->id);
1866         $group1 = $this->getDataGenerator()->create_group([
1867             'courseid' => $course1->id,
1868             'enablemessaging' => 1,
1869             'picturepath' => $CFG->dirroot . '/lib/tests/fixtures/gd-logo.png'
1870         ]);
1872         // Add users to group1.
1873         $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user1->id));
1874         $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user2->id));
1876         // Verify the group with the image works as expected.
1877         $conversations = \core_message\api::get_conversations($user1->id);
1878         $this->assertEquals(2, $conversations[0]->membercount);
1879         $this->assertEquals($course1->shortname, $conversations[0]->subname);
1880         $groupimageurl = get_group_picture_url($group1, $group1->courseid, true);
1881         $this->assertEquals($groupimageurl, $conversations[0]->imageurl);
1883         // Create a group with a linked conversation and without any image.
1884         $group2 = $this->getDataGenerator()->create_group([
1885             'courseid' => $course1->id,
1886             'enablemessaging' => 1,
1887         ]);
1889         // Add users to group2.
1890         $this->getDataGenerator()->create_group_member(array('groupid' => $group2->id, 'userid' => $user2->id));
1891         $this->getDataGenerator()->create_group_member(array('groupid' => $group2->id, 'userid' => $user3->id));
1893         // Verify the group without any image works as expected too.
1894         $conversations = \core_message\api::get_conversations($user3->id);
1895         $this->assertEquals(2, $conversations[0]->membercount);
1896         $this->assertEquals($course1->shortname, $conversations[0]->subname);
1897         $this->assertEquals('https://www.example.com/moodle/theme/image.php/_s/boost/core/1/g/g1', $conversations[0]->imageurl);
1899         // Now, disable the conversation linked to the group and verify it's no longer returned.
1900         $DB->set_field('message_conversations', 'enabled', 0, ['id' => $conversations[0]->id]);
1901         $conversations = \core_message\api::get_conversations($user3->id);
1902         $this->assertCount(0, $conversations);
1903     }
1905    /**
1906     * The data provider for get_conversations_mixed.
1907     *
1908     * This provides sets of data to for testing.
1909     * @return array
1910     */
1911    public function get_conversations_mixed_provider() {
1912        return array(
1913             'Test that conversations with messages contacts is correctly ordered.' => array(
1914                 'users' => array(
1915                     'user1',
1916                     'user2',
1917                     'user3',
1918                 ),
1919                 'contacts' => array(
1920                 ),
1921                 'messages' => array(
1922                     array(
1923                         'from'          => 'user1',
1924                         'to'            => 'user2',
1925                         'state'         => 'unread',
1926                         'subject'       => 'S1',
1927                     ),
1928                     array(
1929                         'from'          => 'user2',
1930                         'to'            => 'user1',
1931                         'state'         => 'unread',
1932                         'subject'       => 'S2',
1933                     ),
1934                     array(
1935                         'from'          => 'user1',
1936                         'to'            => 'user2',
1937                         'state'         => 'unread',
1938                         'timecreated'   => 0,
1939                         'subject'       => 'S3',
1940                     ),
1941                     array(
1942                         'from'          => 'user1',
1943                         'to'            => 'user3',
1944                         'state'         => 'read',
1945                         'timemodifier'  => 1,
1946                         'subject'       => 'S4',
1947                     ),
1948                     array(
1949                         'from'          => 'user3',
1950                         'to'            => 'user1',
1951                         'state'         => 'read',
1952                         'timemodifier'  => 1,
1953                         'subject'       => 'S5',
1954                     ),
1955                     array(
1956                         'from'          => 'user1',
1957                         'to'            => 'user3',
1958                         'state'         => 'read',
1959                         'timecreated'   => 0,
1960                         'subject'       => 'S6',
1961                     ),
1962                 ),
1963                 'expectations' => array(
1964                     'user1' => array(
1965                         // User1 has conversed most recently with user3. The most recent message is M5.
1966                         array(
1967                             'messageposition'   => 0,
1968                             'with'              => 'user3',
1969                             'subject'           => '<p>S5</p>',
1970                             'unreadcount'       => 0,
1971                         ),
1972                         // User1 has also conversed with user2. The most recent message is S2.
1973                         array(
1974                             'messageposition'   => 1,
1975                             'with'              => 'user2',
1976                             'subject'           => '<p>S2</p>',
1977                             'unreadcount'       => 1,
1978                         ),
1979                     ),
1980                     'user2' => array(
1981                         // User2 has only conversed with user1. Their most recent shared message was S2.
1982                         array(
1983                             'messageposition'   => 0,
1984                             'with'              => 'user1',
1985                             'subject'           => '<p>S2</p>',
1986                             'unreadcount'       => 2,
1987                         ),
1988                     ),
1989                     'user3' => array(
1990                         // User3 has only conversed with user1. Their most recent shared message was S5.
1991                         array(
1992                             'messageposition'   => 0,
1993                             'with'              => 'user1',
1994                             'subject'           => '<p>S5</p>',
1995                             'unreadcount'       => 0,
1996                         ),
1997                     ),
1998                 ),
1999             ),
2000             'Test conversations with a single user, where some messages are read and some are not.' => array(
2001                 'users' => array(
2002                     'user1',
2003                     'user2',
2004                 ),
2005                 'contacts' => array(
2006                 ),
2007                 'messages' => array(
2008                     array(
2009                         'from'          => 'user1',
2010                         'to'            => 'user2',
2011                         'state'         => 'read',
2012                         'subject'       => 'S1',
2013                     ),
2014                     array(
2015                         'from'          => 'user2',
2016                         'to'            => 'user1',
2017                         'state'         => 'read',
2018                         'subject'       => 'S2',
2019                     ),
2020                     array(
2021                         'from'          => 'user1',
2022                         'to'            => 'user2',
2023                         'state'         => 'unread',
2024                         'timemodifier'  => 1,
2025                         'subject'       => 'S3',
2026                     ),
2027                     array(
2028                         'from'          => 'user1',
2029                         'to'            => 'user2',
2030                         'state'         => 'unread',
2031                         'timemodifier'  => 1,
2032                         'subject'       => 'S4',
2033                     ),
2034                 ),
2035                 'expectations' => array(
2036                     // The most recent message between user1 and user2 was S4.
2037                     'user1' => array(
2038                         array(
2039                             'messageposition'   => 0,
2040                             'with'              => 'user2',
2041                             'subject'           => '<p>S4</p>',
2042                             'unreadcount'       => 0,
2043                         ),
2044                     ),
2045                     'user2' => array(
2046                         // The most recent message between user1 and user2 was S4.
2047                         array(
2048                             'messageposition'   => 0,
2049                             'with'              => 'user1',
2050                             'subject'           => '<p>S4</p>',
2051                             'unreadcount'       => 2,
2052                         ),
2053                     ),
2054                 ),
2055             ),
2056             'Test conversations with a single user, where some messages are read and some are not, and messages ' .
2057             'are out of order' => array(
2058             // This can happen through a combination of factors including multi-master DB replication with messages
2059             // read somehow (e.g. API).
2060                 'users' => array(
2061                     'user1',
2062                     'user2',
2063                 ),
2064                 'contacts' => array(
2065                 ),
2066                 'messages' => array(
2067                     array(
2068                         'from'          => 'user1',
2069                         'to'            => 'user2',
2070                         'state'         => 'read',
2071                         'subject'       => 'S1',
2072                         'timemodifier'  => 1,
2073                     ),
2074                     array(
2075                         'from'          => 'user2',
2076                         'to'            => 'user1',
2077                         'state'         => 'read',
2078                         'subject'       => 'S2',
2079                         'timemodifier'  => 2,
2080                     ),
2081                     array(
2082                         'from'          => 'user1',
2083                         'to'            => 'user2',
2084                         'state'         => 'unread',
2085                         'subject'       => 'S3',
2086                     ),
2087                     array(
2088                         'from'          => 'user1',
2089                         'to'            => 'user2',
2090                         'state'         => 'unread',
2091                         'subject'       => 'S4',
2092                     ),
2093                 ),
2094                 'expectations' => array(
2095                     // The most recent message between user1 and user2 was S2, even though later IDs have not been read.
2096                     'user1' => array(
2097                         array(
2098                             'messageposition'   => 0,
2099                             'with'              => 'user2',
2100                             'subject'           => '<p>S2</p>',
2101                             'unreadcount'       => 0,
2102                         ),
2103                     ),
2104                     'user2' => array(
2105                         array(
2106                             'messageposition'   => 0,
2107                             'with'              => 'user1',
2108                             'subject'           => '<p>S2</p>',
2109                             'unreadcount'       => 2
2110                         ),
2111                     ),
2112                 ),
2113             ),
2114             'Test unread message count is correct for both users' => array(
2115                 'users' => array(
2116                     'user1',
2117                     'user2',
2118                 ),
2119                 'contacts' => array(
2120                 ),
2121                 'messages' => array(
2122                     array(
2123                         'from'          => 'user1',
2124                         'to'            => 'user2',
2125                         'state'         => 'read',
2126                         'subject'       => 'S1',
2127                         'timemodifier'  => 1,
2128                     ),
2129                     array(
2130                         'from'          => 'user2',
2131                         'to'            => 'user1',
2132                         'state'         => 'read',
2133                         'subject'       => 'S2',
2134                         'timemodifier'  => 2,
2135                     ),
2136                     array(
2137                         'from'          => 'user1',
2138                         'to'            => 'user2',
2139                         'state'         => 'read',
2140                         'subject'       => 'S3',
2141                         'timemodifier'  => 3,
2142                     ),
2143                     array(
2144                         'from'          => 'user1',
2145                         'to'            => 'user2',
2146                         'state'         => 'read',
2147                         'subject'       => 'S4',
2148                         'timemodifier'  => 4,
2149                     ),
2150                     array(
2151                         'from'          => 'user1',
2152                         'to'            => 'user2',
2153                         'state'         => 'unread',
2154                         'subject'       => 'S5',
2155                         'timemodifier'  => 5,
2156                     ),
2157                     array(
2158                         'from'          => 'user2',
2159                         'to'            => 'user1',
2160                         'state'         => 'unread',
2161                         'subject'       => 'S6',
2162                         'timemodifier'  => 6,
2163                     ),
2164                     array(
2165                         'from'          => 'user1',
2166                         'to'            => 'user2',
2167                         'state'         => 'unread',
2168                         'subject'       => 'S7',
2169                         'timemodifier'  => 7,
2170                     ),
2171                     array(
2172                         'from'          => 'user1',
2173                         'to'            => 'user2',
2174                         'state'         => 'unread',
2175                         'subject'       => 'S8',
2176                         'timemodifier'  => 8,
2177                     ),
2178                 ),
2179                 'expectations' => array(
2180                     // The most recent message between user1 and user2 was S2, even though later IDs have not been read.
2181                     'user1' => array(
2182                         array(
2183                             'messageposition'   => 0,
2184                             'with'              => 'user2',
2185                             'subject'           => '<p>S8</p>',
2186                             'unreadcount'       => 1,
2187                         ),
2188                     ),
2189                     'user2' => array(
2190                         array(
2191                             'messageposition'   => 0,
2192                             'with'              => 'user1',
2193                             'subject'           => '<p>S8</p>',
2194                             'unreadcount'       => 3,
2195                         ),
2196                     ),
2197                 ),
2198             ),
2199         );
2200     }
2202     /**
2203      * Test get_conversations with a mixture of messages.
2204      *
2205      * @dataProvider get_conversations_mixed_provider
2206      * @param array $usersdata The list of users to create for this test.
2207      * @param array $messagesdata The list of messages to create.
2208      * @param array $expectations The list of expected outcomes.
2209      */
2210     public function test_get_conversations_mixed($usersdata, $contacts, $messagesdata, $expectations) {
2211         global $DB;
2213         // Create all of the users.
2214         $users = array();
2215         foreach ($usersdata as $username) {
2216             $users[$username] = $this->getDataGenerator()->create_user(array('username' => $username));
2217         }
2219         foreach ($contacts as $username => $contact) {
2220             foreach ($contact as $contactname => $blocked) {
2221                 $record = new stdClass();
2222                 $record->userid     = $users[$username]->id;
2223                 $record->contactid  = $users[$contactname]->id;
2224                 $record->blocked    = $blocked;
2225                 $record->id = $DB->insert_record('message_contacts', $record);
2226             }
2227         }
2229         $defaulttimecreated = time();
2230         foreach ($messagesdata as $messagedata) {
2231             $from       = $users[$messagedata['from']];
2232             $to         = $users[$messagedata['to']];
2233             $subject    = $messagedata['subject'];
2235             if (isset($messagedata['state']) && $messagedata['state'] == 'unread') {
2236                 $messageid = $this->send_fake_message($from, $to, $subject);
2237             } else {
2238                 // If there is no state, or the state is not 'unread', assume the message is read.
2239                 $messageid = message_post_message($from, $to, $subject, FORMAT_PLAIN);
2240             }
2242             $updatemessage = new stdClass();
2243             $updatemessage->id = $messageid;
2244             if (isset($messagedata['timecreated'])) {
2245                 $updatemessage->timecreated = $messagedata['timecreated'];
2246             } else if (isset($messagedata['timemodifier'])) {
2247                 $updatemessage->timecreated = $defaulttimecreated + $messagedata['timemodifier'];
2248             } else {
2249                 $updatemessage->timecreated = $defaulttimecreated;
2250             }
2252             $DB->update_record('messages', $updatemessage);
2253         }
2255         foreach ($expectations as $username => $data) {
2256             // Get the recent conversations for the specified user.
2257             $user = $users[$username];
2258             $conversations = array_values(\core_message\api::get_conversations($user->id));
2259             foreach ($data as $expectation) {
2260                 $otheruser = $users[$expectation['with']];
2261                 $conversation = $conversations[$expectation['messageposition']];
2262                 $this->assertEquals($otheruser->id, $conversation->members[$otheruser->id]->id);
2263                 $this->assertEquals($expectation['subject'], $conversation->messages[0]->text);
2264                 $this->assertEquals($expectation['unreadcount'], $conversation->unreadcount);
2265             }
2266         }
2267     }
2269     /**
2270      * Tests retrieving contacts.
2271      */
2272     public function test_get_contacts() {
2273         // Create some users.
2274         $user1 = self::getDataGenerator()->create_user();
2276         // Set as the user.
2277         $this->setUser($user1);
2279         $user2 = new stdClass();
2280         $user2->firstname = 'User';
2281         $user2->lastname = 'A';
2282         $user2 = self::getDataGenerator()->create_user($user2);
2284         $user3 = new stdClass();
2285         $user3->firstname = 'User';
2286         $user3->lastname = 'B';
2287         $user3 = self::getDataGenerator()->create_user($user3);
2289         $user4 = new stdClass();
2290         $user4->firstname = 'User';
2291         $user4->lastname = 'C';
2292         $user4 = self::getDataGenerator()->create_user($user4);
2294         $user5 = new stdClass();
2295         $user5->firstname = 'User';
2296         $user5->lastname = 'D';
2297         $user5 = self::getDataGenerator()->create_user($user5);
2299         // Add some users as contacts.
2300         \core_message\api::add_contact($user1->id, $user2->id);
2301         \core_message\api::add_contact($user1->id, $user3->id);
2302         \core_message\api::add_contact($user1->id, $user4->id);
2304         // Retrieve the contacts.
2305         $contacts = \core_message\api::get_contacts($user1->id);
2307         // Confirm the data is correct.
2308         $this->assertEquals(3, count($contacts));
2309         usort($contacts, ['static', 'sort_contacts']);
2311         $contact1 = $contacts[0];
2312         $contact2 = $contacts[1];
2313         $contact3 = $contacts[2];
2315         $this->assertEquals($user2->id, $contact1->userid);
2316         $this->assertEmpty($contact1->useridfrom);
2317         $this->assertFalse($contact1->ismessaging);
2318         $this->assertNull($contact1->lastmessage);
2319         $this->assertNull($contact1->messageid);
2320         $this->assertNull($contact1->isonline);
2321         $this->assertFalse($contact1->isread);
2322         $this->assertFalse($contact1->isblocked);
2323         $this->assertNull($contact1->unreadcount);
2325         $this->assertEquals($user3->id, $contact2->userid);
2326         $this->assertEmpty($contact2->useridfrom);
2327         $this->assertFalse($contact2->ismessaging);
2328         $this->assertNull($contact2->lastmessage);
2329         $this->assertNull($contact2->messageid);
2330         $this->assertNull($contact2->isonline);
2331         $this->assertFalse($contact2->isread);
2332         $this->assertFalse($contact2->isblocked);
2333         $this->assertNull($contact2->unreadcount);
2335         $this->assertEquals($user4->id, $contact3->userid);
2336         $this->assertEmpty($contact3->useridfrom);
2337         $this->assertFalse($contact3->ismessaging);
2338         $this->assertNull($contact3->lastmessage);
2339         $this->assertNull($contact3->messageid);
2340         $this->assertNull($contact3->isonline);
2341         $this->assertFalse($contact3->isread);
2342         $this->assertFalse($contact3->isblocked);
2343         $this->assertNull($contact3->unreadcount);
2344     }
2346     /**
2347      * Tests retrieving user contacts.
2348      */
2349     public function test_get_user_contacts() {
2350         // Create some users.
2351         $user1 = self::getDataGenerator()->create_user();
2353         // Set as the user.
2354         $this->setUser($user1);
2356         $user2 = new stdClass();
2357         $user2->firstname = 'User';
2358         $user2->lastname = 'A';
2359         $user2 = self::getDataGenerator()->create_user($user2);
2361         $user3 = new stdClass();
2362         $user3->firstname = 'User';
2363         $user3->lastname = 'B';
2364         $user3 = self::getDataGenerator()->create_user($user3);
2366         $user4 = new stdClass();
2367         $user4->firstname = 'User';
2368         $user4->lastname = 'C';
2369         $user4 = self::getDataGenerator()->create_user($user4);
2371         $user5 = new stdClass();
2372         $user5->firstname = 'User';
2373         $user5->lastname = 'D';
2374         $user5 = self::getDataGenerator()->create_user($user5);
2376         // Add some users as contacts.
2377         \core_message\api::add_contact($user1->id, $user2->id);
2378         \core_message\api::add_contact($user1->id, $user3->id);
2379         \core_message\api::add_contact($user1->id, $user4->id);
2381         // Retrieve the contacts.
2382         $contacts = \core_message\api::get_user_contacts($user1->id);
2384         // Confirm the data is correct.
2385         $this->assertEquals(3, count($contacts));
2387         ksort($contacts);
2389         $contact1 = array_shift($contacts);
2390         $contact2 = array_shift($contacts);
2391         $contact3 = array_shift($contacts);
2393         $this->assertEquals($user2->id, $contact1->id);
2394         $this->assertEquals(fullname($user2), $contact1->fullname);
2395         $this->assertTrue($contact1->iscontact);
2397         $this->assertEquals($user3->id, $contact2->id);
2398         $this->assertEquals(fullname($user3), $contact2->fullname);
2399         $this->assertTrue($contact2->iscontact);
2401         $this->assertEquals($user4->id, $contact3->id);
2402         $this->assertEquals(fullname($user4), $contact3->fullname);
2403         $this->assertTrue($contact3->iscontact);
2404     }
2406     /**
2407      * Tests retrieving messages.
2408      */
2409     public function test_get_messages() {
2410         // Create some users.
2411         $user1 = self::getDataGenerator()->create_user();
2412         $user2 = self::getDataGenerator()->create_user();
2414         // The person doing the search.
2415         $this->setUser($user1);
2417         // Send some messages back and forth.
2418         $time = 1;
2419         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
2420         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
2421         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
2422         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
2424         // Retrieve the messages.
2425         $messages = \core_message\api::get_messages($user1->id, $user2->id);
2427         // Confirm the message data is correct.
2428         $this->assertEquals(4, count($messages));
2430         $message1 = $messages[0];
2431         $message2 = $messages[1];
2432         $message3 = $messages[2];
2433         $message4 = $messages[3];
2435         $this->assertEquals($user1->id, $message1->useridfrom);
2436         $this->assertEquals($user2->id, $message1->useridto);
2437         $this->assertTrue($message1->displayblocktime);
2438         $this->assertContains('Yo!', $message1->text);
2440         $this->assertEquals($user2->id, $message2->useridfrom);
2441         $this->assertEquals($user1->id, $message2->useridto);
2442         $this->assertFalse($message2->displayblocktime);
2443         $this->assertContains('Sup mang?', $message2->text);
2445         $this->assertEquals($user1->id, $message3->useridfrom);
2446         $this->assertEquals($user2->id, $message3->useridto);
2447         $this->assertFalse($message3->displayblocktime);
2448         $this->assertContains('Writing PHPUnit tests!', $message3->text);
2450         $this->assertEquals($user2->id, $message4->useridfrom);
2451         $this->assertEquals($user1->id, $message4->useridto);
2452         $this->assertFalse($message4->displayblocktime);
2453         $this->assertContains('Word.', $message4->text);
2454     }
2456     /**
2457      * Tests retrieving conversation messages.
2458      */
2459     public function test_get_conversation_messages() {
2460         // Create some users.
2461         $user1 = self::getDataGenerator()->create_user();
2462         $user2 = self::getDataGenerator()->create_user();
2464         // Create conversation.
2465         $conversation = \core_message\api::create_conversation(
2466             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
2467             [$user1->id, $user2->id]
2468         );
2470         // The person doing the search.
2471         $this->setUser($user1);
2473         // Send some messages back and forth.
2474         $time = 1;
2475         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time + 1);
2476         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 2);
2477         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Writing PHPUnit tests!', $time + 3);
2478         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Word.', $time + 4);
2480         // Retrieve the messages.
2481         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id);
2483         // Confirm the conversation id is correct.
2484         $this->assertEquals($conversation->id, $convmessages['id']);
2486         // Confirm the message data is correct.
2487         $messages = $convmessages['messages'];
2488         $this->assertEquals(4, count($messages));
2489         $message1 = $messages[0];
2490         $message2 = $messages[1];
2491         $message3 = $messages[2];
2492         $message4 = $messages[3];
2494         $this->assertEquals($user1->id, $message1->useridfrom);
2495         $this->assertContains('Yo!', $message1->text);
2497         $this->assertEquals($user2->id, $message2->useridfrom);
2498         $this->assertContains('Sup mang?', $message2->text);
2500         $this->assertEquals($user1->id, $message3->useridfrom);
2501         $this->assertContains('Writing PHPUnit tests!', $message3->text);
2503         $this->assertEquals($user1->id, $message4->useridfrom);
2504         $this->assertContains('Word.', $message4->text);
2506         // Confirm the members data is correct.
2507         $members = $convmessages['members'];
2508         $this->assertEquals(2, count($members));
2509     }
2511     /**
2512      * Tests retrieving group conversation messages.
2513      */
2514     public function test_get_group_conversation_messages() {
2515         // Create some users.
2516         $user1 = self::getDataGenerator()->create_user();
2517         $user2 = self::getDataGenerator()->create_user();
2518         $user3 = self::getDataGenerator()->create_user();
2519         $user4 = self::getDataGenerator()->create_user();
2521         // Create group conversation.
2522         $conversation = \core_message\api::create_conversation(
2523             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2524             [$user1->id, $user2->id, $user3->id, $user4->id]
2525         );
2527         // The person doing the search.
2528         $this->setUser($user1);
2530         // Send some messages back and forth.
2531         $time = 1;
2532         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time + 1);
2533         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 2);
2534         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Writing PHPUnit tests!', $time + 3);
2535         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Word.', $time + 4);
2536         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Yeah!', $time + 5);
2538         // Retrieve the messages.
2539         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id);
2541         // Confirm the conversation id is correct.
2542         $this->assertEquals($conversation->id, $convmessages['id']);
2544         // Confirm the message data is correct.
2545         $messages = $convmessages['messages'];
2546         $this->assertEquals(5, count($messages));
2548         $message1 = $messages[0];
2549         $message2 = $messages[1];
2550         $message3 = $messages[2];
2551         $message4 = $messages[3];
2552         $message5 = $messages[4];
2554         $this->assertEquals($user1->id, $message1->useridfrom);
2555         $this->assertContains('Yo!', $message1->text);
2557         $this->assertEquals($user2->id, $message2->useridfrom);
2558         $this->assertContains('Sup mang?', $message2->text);
2560         $this->assertEquals($user3->id, $message3->useridfrom);
2561         $this->assertContains('Writing PHPUnit tests!', $message3->text);
2563         $this->assertEquals($user1->id, $message4->useridfrom);
2564         $this->assertContains('Word.', $message4->text);
2566         $this->assertEquals($user2->id, $message5->useridfrom);
2567         $this->assertContains('Yeah!', $message5->text);
2569         // Confirm the members data is correct.
2570         $members = $convmessages['members'];
2571         $this->assertEquals(3, count($members));
2572     }
2574     /**
2575      * Test verifying the sorting param for get_conversation_messages is respected().
2576      */
2577     public function test_get_conversation_messages_sorting() {
2578         // Create some users.
2579         $user1 = self::getDataGenerator()->create_user();
2580         $user2 = self::getDataGenerator()->create_user();
2581         $user3 = self::getDataGenerator()->create_user();
2583         // Create conversations - 1 group and 1 individual.
2584         $conversation = \core_message\api::create_conversation(
2585             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
2586             [$user1->id, $user2->id]
2587         );
2588         $conversation2 = \core_message\api::create_conversation(
2589             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2590             [$user1->id, $user2->id, $user3->id]
2591         );
2593         // Send some messages back and forth.
2594         $time = 1;
2595         $m1id = testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time + 1);
2596         $m2id = testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 2);
2597         $m3id = testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Writing PHPUnit tests!', $time + 3);
2598         $m4id = testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Word.', $time + 4);
2600         $gm1id = testhelper::send_fake_message_to_conversation($user1, $conversation2->id, 'Yo!', $time + 1);
2601         $gm2id = testhelper::send_fake_message_to_conversation($user2, $conversation2->id, 'Sup mang?', $time + 2);
2602         $gm3id = testhelper::send_fake_message_to_conversation($user3, $conversation2->id, 'Writing PHPUnit tests!', $time + 3);
2603         $gm4id = testhelper::send_fake_message_to_conversation($user1, $conversation2->id, 'Word.', $time + 4);
2605         // The person doing the search.
2606         $this->setUser($user1);
2608         // Retrieve the messages using default sort ('timecreated ASC') and verify ordering.
2609         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id);
2610         $messages = $convmessages['messages'];
2611         $this->assertEquals($m1id, $messages[0]->id);
2612         $this->assertEquals($m2id, $messages[1]->id);
2613         $this->assertEquals($m3id, $messages[2]->id);
2614         $this->assertEquals($m4id, $messages[3]->id);
2616         // Retrieve the messages without specifying DESC sort ordering, and verify ordering.
2617         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0, 'timecreated DESC');
2618         $messages = $convmessages['messages'];
2619         $this->assertEquals($m1id, $messages[3]->id);
2620         $this->assertEquals($m2id, $messages[2]->id);
2621         $this->assertEquals($m3id, $messages[1]->id);
2622         $this->assertEquals($m4id, $messages[0]->id);
2624         // Retrieve the messages using default sort ('timecreated ASC') and verify ordering.
2625         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation2->id);
2626         $messages = $convmessages['messages'];
2627         $this->assertEquals($gm1id, $messages[0]->id);
2628         $this->assertEquals($gm2id, $messages[1]->id);
2629         $this->assertEquals($gm3id, $messages[2]->id);
2630         $this->assertEquals($gm4id, $messages[3]->id);
2632         // Retrieve the messages without specifying DESC sort ordering, and verify ordering.
2633         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation2->id, 0, 0, 'timecreated DESC');
2634         $messages = $convmessages['messages'];
2635         $this->assertEquals($gm1id, $messages[3]->id);
2636         $this->assertEquals($gm2id, $messages[2]->id);
2637         $this->assertEquals($gm3id, $messages[1]->id);
2638         $this->assertEquals($gm4id, $messages[0]->id);
2639     }
2641     /**
2642      * Test retrieving conversation messages by providing a minimum timecreated value.
2643      */
2644     public function test_get_conversation_messages_time_from_only() {
2645         // Create some users.
2646         $user1 = self::getDataGenerator()->create_user();
2647         $user2 = self::getDataGenerator()->create_user();
2648         $user3 = self::getDataGenerator()->create_user();
2649         $user4 = self::getDataGenerator()->create_user();
2651         // Create group conversation.
2652         $conversation = \core_message\api::create_conversation(
2653             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2654             [$user1->id, $user2->id, $user3->id, $user4->id]
2655         );
2657         // The person doing the search.
2658         $this->setUser($user1);
2660         // Send some messages back and forth.
2661         $time = 1;
2662         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2663         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2664         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2665         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2667         // Retrieve the messages from $time, which should be all of them.
2668         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0, 'timecreated ASC', $time);
2670         // Confirm the conversation id is correct.
2671         $this->assertEquals($conversation->id, $convmessages['id']);
2673         // Confirm the message data is correct.
2674         $messages = $convmessages['messages'];
2675         $this->assertEquals(4, count($messages));
2677         $message1 = $messages[0];
2678         $message2 = $messages[1];
2679         $message3 = $messages[2];
2680         $message4 = $messages[3];
2682         $this->assertContains('Message 1', $message1->text);
2683         $this->assertContains('Message 2', $message2->text);
2684         $this->assertContains('Message 3', $message3->text);
2685         $this->assertContains('Message 4', $message4->text);
2687         // Confirm the members data is correct.
2688         $members = $convmessages['members'];
2689         $this->assertEquals(3, count($members));
2691         // Retrieve the messages from $time + 3, which should only be the 2 last messages.
2692         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0,
2693             'timecreated ASC', $time + 3);
2695         // Confirm the conversation id is correct.
2696         $this->assertEquals($conversation->id, $convmessages['id']);
2698         // Confirm the message data is correct.
2699         $messages = $convmessages['messages'];
2700         $this->assertEquals(2, count($messages));
2702         $message1 = $messages[0];
2703         $message2 = $messages[1];
2705         $this->assertContains('Message 3', $message1->text);
2706         $this->assertContains('Message 4', $message2->text);
2708         // Confirm the members data is correct.
2709         $members = $convmessages['members'];
2710         $this->assertEquals(2, count($members));
2711     }
2713     /**
2714      * Test retrieving conversation messages by providing a maximum timecreated value.
2715      */
2716     public function test_get_conversation_messages_time_to_only() {
2717         // Create some users.
2718         $user1 = self::getDataGenerator()->create_user();
2719         $user2 = self::getDataGenerator()->create_user();
2720         $user3 = self::getDataGenerator()->create_user();
2721         $user4 = self::getDataGenerator()->create_user();
2723         // Create group conversation.
2724         $conversation = \core_message\api::create_conversation(
2725             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2726             [$user1->id, $user2->id, $user3->id, $user4->id]
2727         );
2729         // The person doing the search.
2730         $this->setUser($user1);
2732         // Send some messages back and forth.
2733         $time = 1;
2734         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2735         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2736         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2737         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2739         // Retrieve the messages up until $time + 4, which should be all of them.
2740         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0, 'timecreated ASC',
2741             0, $time + 4);
2743         // Confirm the conversation id is correct.
2744         $this->assertEquals($conversation->id, $convmessages['id']);
2746         // Confirm the message data is correct.
2747         $messages = $convmessages['messages'];
2748         $this->assertEquals(4, count($messages));
2750         $message1 = $messages[0];
2751         $message2 = $messages[1];
2752         $message3 = $messages[2];
2753         $message4 = $messages[3];
2755         $this->assertContains('Message 1', $message1->text);
2756         $this->assertContains('Message 2', $message2->text);
2757         $this->assertContains('Message 3', $message3->text);
2758         $this->assertContains('Message 4', $message4->text);
2760         // Confirm the members data is correct.
2761         $members = $convmessages['members'];
2762         $this->assertEquals(3, count($members));
2764         // Retrieve the messages up until $time + 2, which should be the first two.
2765         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0, 'timecreated ASC',
2766             0, $time + 2);
2768         // Confirm the conversation id is correct.
2769         $this->assertEquals($conversation->id, $convmessages['id']);
2771         // Confirm the message data is correct.
2772         $messages = $convmessages['messages'];
2773         $this->assertEquals(2, count($messages));
2775         $message1 = $messages[0];
2776         $message2 = $messages[1];
2778         $this->assertContains('Message 1', $message1->text);
2779         $this->assertContains('Message 2', $message2->text);
2781         // Confirm the members data is correct.
2782         $members = $convmessages['members'];
2783         $this->assertEquals(2, count($members));
2784     }
2786     /**
2787      * Test retrieving conversation messages by providing a minimum and maximum timecreated value.
2788      */
2789     public function test_get_conversation_messages_time_from_and_to() {
2790         // Create some users.
2791         $user1 = self::getDataGenerator()->create_user();
2792         $user2 = self::getDataGenerator()->create_user();
2793         $user3 = self::getDataGenerator()->create_user();
2794         $user4 = self::getDataGenerator()->create_user();
2796         // Create group conversation.
2797         $conversation = \core_message\api::create_conversation(
2798             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2799             [$user1->id, $user2->id, $user3->id, $user4->id]
2800         );
2802         // The person doing the search.
2803         $this->setUser($user1);
2805         // Send some messages back and forth.
2806         $time = 1;
2807         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2808         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2809         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2810         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2812         // Retrieve the messages from $time + 2 up until $time + 3, which should be 2nd and 3rd message.
2813         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 0, 0,
2814             'timecreated ASC', $time + 2, $time + 3);
2816         // Confirm the conversation id is correct.
2817         $this->assertEquals($conversation->id, $convmessages['id']);
2819         // Confirm the message data is correct.
2820         $messages = $convmessages['messages'];
2821         $this->assertEquals(2, count($messages));
2823         $message1 = $messages[0];
2824         $message2 = $messages[1];
2826         $this->assertContains('Message 2', $message1->text);
2827         $this->assertContains('Message 3', $message2->text);
2829         // Confirm the members data is correct.
2830         $members = $convmessages['members'];
2831         $this->assertEquals(2, count($members));
2832     }
2835     /**
2836      * Test retrieving conversation messages by providing a limitfrom value.
2837      */
2838     public function test_get_conversation_messages_limitfrom_only() {
2839         // Create some users.
2840         $user1 = self::getDataGenerator()->create_user();
2841         $user2 = self::getDataGenerator()->create_user();
2842         $user3 = self::getDataGenerator()->create_user();
2843         $user4 = self::getDataGenerator()->create_user();
2845         // Create group conversation.
2846         $conversation = \core_message\api::create_conversation(
2847             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2848             [$user1->id, $user2->id, $user3->id, $user4->id]
2849         );
2851         // The person doing the search.
2852         $this->setUser($user1);
2854         // Send some messages back and forth.
2855         $time = 1;
2856         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2857         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2858         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2859         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2861         // Retrieve the messages from $time, which should be all of them.
2862         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 2);
2864         // Confirm the conversation id is correct.
2865         $messages = $convmessages['messages'];
2866         $this->assertEquals($conversation->id, $convmessages['id']);
2868         // Confirm the message data is correct.
2869         $this->assertEquals(2, count($messages));
2871         $message1 = $messages[0];
2872         $message2 = $messages[1];
2874         $this->assertContains('Message 3', $message1->text);
2875         $this->assertContains('Message 4', $message2->text);
2877         // Confirm the members data is correct.
2878         $members = $convmessages['members'];
2879         $this->assertEquals(2, count($members));
2880     }
2882     /**
2883      * Test retrieving conversation messages by providing a limitnum value.
2884      */
2885     public function test_get_conversation_messages_limitnum() {
2886         // Create some users.
2887         $user1 = self::getDataGenerator()->create_user();
2888         $user2 = self::getDataGenerator()->create_user();
2889         $user3 = self::getDataGenerator()->create_user();
2890         $user4 = self::getDataGenerator()->create_user();
2892         // Create group conversation.
2893         $conversation = \core_message\api::create_conversation(
2894             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2895             [$user1->id, $user2->id, $user3->id, $user4->id]
2896         );
2898         // The person doing the search.
2899         $this->setUser($user1);
2901         // Send some messages back and forth.
2902         $time = 1;
2903         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2904         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2905         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2906         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2908         // Retrieve the messages from $time, which should be all of them.
2909         $convmessages = \core_message\api::get_conversation_messages($user1->id, $conversation->id, 2, 1);
2911         // Confirm the conversation id is correct.
2912         $messages = $convmessages['messages'];
2913         $this->assertEquals($conversation->id, $convmessages['id']);
2915         // Confirm the message data is correct.
2916         $messages = $convmessages['messages'];
2917         $this->assertEquals(1, count($messages));
2919         $message1 = $messages[0];
2921         $this->assertContains('Message 3', $message1->text);
2923         // Confirm the members data is correct.
2924         $members = $convmessages['members'];
2925         $this->assertEquals(1, count($members));
2926     }
2928     /**
2929      * Tests retrieving most recent message.
2930      */
2931     public function test_get_most_recent_message() {
2932         // Create some users.
2933         $user1 = self::getDataGenerator()->create_user();
2934         $user2 = self::getDataGenerator()->create_user();
2936         // The person doing the search.
2937         $this->setUser($user1);
2939         // Send some messages back and forth.
2940         $time = 1;
2941         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
2942         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
2943         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
2944         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
2946         // Retrieve the most recent messages.
2947         $message = \core_message\api::get_most_recent_message($user1->id, $user2->id);
2949         // Check the results are correct.
2950         $this->assertEquals($user2->id, $message->useridfrom);
2951         $this->assertEquals($user1->id, $message->useridto);
2952         $this->assertContains('Word.', $message->text);
2953     }
2955     /**
2956      * Tests retrieving most recent conversation message.
2957      */
2958     public function test_get_most_recent_conversation_message() {
2959         // Create some users.
2960         $user1 = self::getDataGenerator()->create_user();
2961         $user2 = self::getDataGenerator()->create_user();
2962         $user3 = self::getDataGenerator()->create_user();
2964         // Create group conversation.
2965         $conversation = \core_message\api::create_conversation(
2966             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2967             [$user1->id, $user2->id, $user3->id]
2968         );
2970         // The person getting the most recent conversation message.
2971         $this->setUser($user1);
2973         // Send some messages back and forth.
2974         $time = 1;
2975         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time + 1);
2976         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 2);
2977         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Writing PHPUnit tests!', $time + 3);
2978         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Word.', $time + 4);
2980         // Retrieve the most recent messages.
2981         $message = \core_message\api::get_most_recent_conversation_message($conversation->id, $user1->id);
2983         // Check the results are correct.
2984         $this->assertEquals($user2->id, $message->useridfrom);
2985         $this->assertContains('Word.', $message->text);
2986     }
2988     /**
2989      * Tests retrieving a user's profile.
2990      */
2991     public function test_get_profile() {
2992         // Create some users.
2993         $user1 = self::getDataGenerator()->create_user();
2995         $user2 = new stdClass();
2996         $user2->country = 'AU';
2997         $user2->city = 'Perth';
2998         $user2 = self::getDataGenerator()->create_user($user2);
3000         // The person doing the search.
3001         $this->setUser($user1);
3003         // Get the profile.
3004         $profile = \core_message\api::get_profile($user1->id, $user2->id);
3006         $this->assertEquals($user2->id, $profile->userid);
3007         $this->assertEmpty($profile->email);
3008         $this->assertEmpty($profile->country);
3009         $this->assertEmpty($profile->city);
3010         $this->assertEquals(fullname($user2), $profile->fullname);
3011         $this->assertNull($profile->isonline);
3012         $this->assertFalse($profile->isblocked);
3013         $this->assertFalse($profile->iscontact);
3014     }
3016     /**
3017      * Tests retrieving a user's profile.
3018      */
3019     public function test_get_profile_as_admin() {
3020         // The person doing the search.
3021         $this->setAdminUser();
3023         // Create some users.
3024         $user1 = self::getDataGenerator()->create_user();
3026         $user2 = new stdClass();
3027         $user2->country = 'AU';
3028         $user2->city = 'Perth';
3029         $user2 = self::getDataGenerator()->create_user($user2);
3031         // Get the profile.
3032         $profile = \core_message\api::get_profile($user1->id, $user2->id);
3034         $this->assertEquals($user2->id, $profile->userid);
3035         $this->assertEquals($user2->email, $profile->email);
3036         $this->assertEquals($user2->country, $profile->country);
3037         $this->assertEquals($user2->city, $profile->city);
3038         $this->assertEquals(fullname($user2), $profile->fullname);
3039         $this->assertFalse($profile->isonline);
3040         $this->assertFalse($profile->isblocked);
3041         $this->assertFalse($profile->iscontact);
3042     }
3044     /**
3045      * Tests checking if a user can mark all messages as read.
3046      */
3047     public function test_can_mark_all_messages_as_read() {
3048         // Set as the admin.
3049         $this->setAdminUser();
3051         // Create some users.
3052         $user1 = self::getDataGenerator()->create_user();
3053         $user2 = self::getDataGenerator()->create_user();
3054         $user3 = self::getDataGenerator()->create_user();
3056         // Send some messages back and forth.
3057         $time = 1;
3058         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
3059         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
3060         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
3061         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
3063         $conversationid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
3065         // The admin can do anything.
3066         $this->assertTrue(\core_message\api::can_mark_all_messages_as_read($user1->id, $conversationid));
3068         // Set as the user 1.
3069         $this->setUser($user1);
3071         // The user can mark the messages as he is in the conversation.
3072         $this->assertTrue(\core_message\api::can_mark_all_messages_as_read($user1->id, $conversationid));
3074         // User 1 can not mark the messages read for user 2.
3075         $this->assertFalse(\core_message\api::can_mark_all_messages_as_read($user2->id, $conversationid));
3077         // This user is not a part of the conversation.
3078         $this->assertFalse(\core_message\api::can_mark_all_messages_as_read($user3->id, $conversationid));
3079     }
3081     /**
3082      * Tests checking if a user can delete a conversation.
3083      */
3084     public function test_can_delete_conversation() {
3085         // Set as the admin.
3086         $this->setAdminUser();
3088         // Create some users.
3089         $user1 = self::getDataGenerator()->create_user();
3090         $user2 = self::getDataGenerator()->create_user();
3092         // Send some messages back and forth.
3093         $time = 1;
3094         $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
3095         $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
3096         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
3097         $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
3099         $conversationid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
3101         // The admin can do anything.
3102         $this->assertTrue(\core_message\api::can_delete_conversation($user1->id, $conversationid));
3104         // Set as the user 1.
3105         $this->setUser($user1);
3107         // They can delete their own messages.
3108         $this->assertTrue(\core_message\api::can_delete_conversation($user1->id, $conversationid));
3110         // They can't delete someone elses.
3111         $this->assertFalse(\core_message\api::can_delete_conversation($user2->id, $conversationid));
3112     }
3114     /**
3115      * Tests deleting a conversation.
3116      */
3117     public function test_delete_conversation() {
3118         global $DB;
3120         // Create some users.
3121         $user1 = self::getDataGenerator()->create_user();
3122         $user2 = self::getDataGenerator()->create_user();
3124         // The person doing the search.
3125         $this->setUser($user1);
3127         // Send some messages back and forth.
3128         $time = 1;
3129         $m1id = $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
3130         $m2id = $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
3131         $m3id = $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
3132         $m4id = $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
3134         // Delete the conversation as user 1.
3135         \core_message\api::delete_conversation($user1->id, $user2->id);
3136         $this->assertDebuggingCalled();
3138         $muas = $DB->get_records('message_user_actions', array(), 'timecreated ASC');
3139         $this->assertCount(4, $muas);
3140         // Sort by id.
3141         ksort($muas);
3143         $mua1 = array_shift($muas);
3144         $mua2 = array_shift($muas);
3145         $mua3 = array_shift($muas);
3146         $mua4 = array_shift($muas);
3148         $this->assertEquals($user1->id, $mua1->userid);
3149         $this->assertEquals($m1id, $mua1->messageid);
3150         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua1->action);
3152         $this->assertEquals($user1->id, $mua2->userid);
3153         $this->assertEquals($m2id, $mua2->messageid);
3154         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua2->action);
3156         $this->assertEquals($user1->id, $mua3->userid);
3157         $this->assertEquals($m3id, $mua3->messageid);
3158         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua3->action);
3160         $this->assertEquals($user1->id, $mua4->userid);
3161         $this->assertEquals($m4id, $mua4->messageid);
3162         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua4->action);
3163     }
3165     /**
3166      * Tests deleting a conversation by conversation id.
3167      */
3168     public function test_delete_conversation_by_id() {
3169         global $DB;
3171         // Create some users.
3172         $user1 = self::getDataGenerator()->create_user();
3173         $user2 = self::getDataGenerator()->create_user();
3175         // The person doing the search.
3176         $this->setUser($user1);
3178         // Create self-conversation.
3179         $sc1 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_SELF, [$user1->id]);
3180         $sc2 = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_SELF, [$user2->id]);
3182         // Send some messages back and forth.
3183         $time = 1;
3184         $m1id = $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
3185         $m2id = $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
3186         $m3id = $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
3187         $m4id = $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
3188         $m5id = testhelper::send_fake_message_to_conversation($user1, $sc1->id, 'Hi to myself!', $time + 5);
3189         $m6id = testhelper::send_fake_message_to_conversation($user2, $sc2->id, 'I am talking with myself', $time + 6);
3191         $conversationid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
3193         // Delete the individual conversation between user1 and user2 (only for user1).
3194         \core_message\api::delete_conversation_by_id($user1->id, $conversationid);
3196         $muas = $DB->get_records('message_user_actions', array(), 'timecreated ASC');
3197         $this->assertCount(4, $muas);
3198         // Sort by id.
3199         ksort($muas);
3201         $mua1 = array_shift($muas);
3202         $mua2 = array_shift($muas);
3203         $mua3 = array_shift($muas);
3204         $mua4 = array_shift($muas);
3206         $this->assertEquals($user1->id, $mua1->userid);
3207         $this->assertEquals($m1id, $mua1->messageid);
3208         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua1->action);
3210         $this->assertEquals($user1->id, $mua2->userid);
3211         $this->assertEquals($m2id, $mua2->messageid);
3212         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua2->action);
3214         $this->assertEquals($user1->id, $mua3->userid);
3215         $this->assertEquals($m3id, $mua3->messageid);
3216         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua3->action);
3218         $this->assertEquals($user1->id, $mua4->userid);
3219         $this->assertEquals($m4id, $mua4->messageid);
3220         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua4->action);
3222         // Delete the self-conversation as user 1.
3223         \core_message\api::delete_conversation_by_id($user1->id, $sc1->id);
3225         $muas = $DB->get_records('message_user_actions', array(), 'timecreated ASC');
3226         $this->assertCount(5, $muas);
3228         // Sort by id.
3229         ksort($muas);
3231         $mua1 = array_shift($muas);
3232         $mua2 = array_shift($muas);
3233         $mua3 = array_shift($muas);
3234         $mua4 = array_shift($muas);
3235         $mua5 = array_shift($muas);
3237         // Check only messages in self-conversion for user1 are deleted (self-conversation for user2 shouldn't be removed).
3238         $this->assertEquals($user1->id, $mua5->userid);
3239         $this->assertEquals($m5id, $mua5->messageid);
3240         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua5->action);
3241     }
3243     /**
3244      * Tests counting unread conversations.
3245      */
3246     public function test_count_unread_conversations() {
3247         $this->resetAfterTest(true);
3249         // Create some users.
3250         $user1 = self::getDataGenerator()->create_user();
3251         $user2 = self::getDataGenerator()->create_user();
3252         $user3 = self::getDataGenerator()->create_user();
3253         $user4 = self::getDataGenerator()->create_user();
3255         // The person wanting the conversation count.
3256         $this->setUser($user1);
3258         // Send some messages back and forth, have some different conversations with different users.
3259         $this->send_fake_message($user1, $user2, 'Yo!');
3260         $this->send_fake_message($user2, $user1, 'Sup mang?');
3261         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!');
3262         $this->send_fake_message($user2, $user1, 'Word.');
3264         $this->send_fake_message($user1, $user3, 'Booyah');
3265         $this->send_fake_message($user3, $user1, 'Whaaat?');
3266         $this->send_fake_message($user1, $user3, 'Nothing.');
3267         $this->send_fake_message($user3, $user1, 'Cool.');
3269         $this->send_fake_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?');
3270         $this->send_fake_message($user4, $user1, 'Yah brah, it\'s pretty rad.');
3271         $this->send_fake_message($user1, $user4, 'Dope.');
3273         // Check the amount for the current user.
3274         $this->assertEquals(3, core_message\api::count_unread_conversations());
3276         // Check the amount for the second user.
3277         $this->assertEquals(1, core_message\api::count_unread_conversations($user2));
3278     }
3280     /**
3281      * Tests counting unread conversations where one conversation is disabled.
3282      */
3283     public function test_count_unread_conversations_disabled() {
3284         $this->resetAfterTest(true);
3286         // Create some users.
3287         $user1 = self::getDataGenerator()->create_user();
3288         $user2 = self::getDataGenerator()->create_user();
3289         $user3 = self::getDataGenerator()->create_user();
3290         $user4 = self::getDataGenerator()->create_user();
3292         // The person wanting the conversation count.
3293         $this->setUser($user1);
3295         // Send some messages back and forth, have some different conversations with different users.
3296         $this->send_fake_message($user1, $user2, 'Yo!');
3297         $this->send_fake_message($user2, $user1, 'Sup mang?');
3298         $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!');
3299         $this->send_fake_message($user2, $user1, 'Word.');
3301         $this->send_fake_message($user1, $user3, 'Booyah');
3302         $this->send_fake_message($user3, $user1, 'Whaaat?');
3303         $this->send_fake_message($user1, $user3, 'Nothing.');
3304         $this->send_fake_message($user3, $user1, 'Cool.');
3306         $this->send_fake_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?');
3307         $this->send_fake_message($user4, $user1, 'Yah brah, it\'s pretty rad.');
3308         $this->send_fake_message($user1, $user4, 'Dope.');
3310         // Let's disable the last conversation.
3311         $conversationid = core_message\api::get_conversation_between_users([$user1->id, $user4->id]);
3312         core_message\api::disable_conversation($conversationid);
3314         // Check that the disabled conversation was not included.
3315         $this->assertEquals(2, core_message\api::count_unread_conversations());
3316     }
3318     /**
3319      * Tests deleting a conversation.
3320      */
3321     public function test_get_all_message_preferences() {
3322         $user = self::getDataGenerator()->create_user();
3323         $this->setUser($user);
3325         // Set a couple of preferences to test.
3326         set_user_preference('message_provider_mod_assign_assign_notification_loggedin', 'popup', $user);
3327         set_user_preference('message_provider_mod_assign_assign_notification_loggedoff', 'email', $user);
3329         $processors = get_message_processors();
3330         $providers = message_get_providers_for_user($user->id);
3331         $prefs = \core_message\api::get_all_message_preferences($processors, $providers, $user);
3333         $this->assertEquals(1, $prefs->mod_assign_assign_notification_loggedin['popup']);
3334         $this->assertEquals(1, $prefs->mod_assign_assign_notification_loggedoff['email']);
3335     }
3337     /**
3338      * Tests the user can post a message.
3339      */
3340     public function test_can_post_message() {
3341         // Create some users.
3342         $user1 = self::getDataGenerator()->create_user();
3343         $user2 = self::getDataGenerator()->create_user();
3345         // Set as the first user.
3346         $this->setUser($user1);
3348         // With the default privacy setting, users can't message them.
3349         $this->assertFalse(\core_message\api::can_post_message($user2));
3351         // Enrol users to the same course.
3352         $course = $this->getDataGenerator()->create_course();
3353         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3354         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3355         // After enrolling users to the course, they should be able to message them with the default privacy setting.
3356         $this->assertTrue(\core_message\api::can_post_message($user2));
3357     }
3359     /**
3360      * Tests the user can't post a message without proper capability.
3361      */
3362     public function test_can_post_message_without_sendmessage_cap() {
3363         global $DB;
3365         // Create some users.
3366         $user1 = self::getDataGenerator()->create_user();
3367         $user2 = self::getDataGenerator()->create_user();
3369         // Set as the user 1.
3370         $this->setUser($user1);
3372         // Remove the capability to send a message.
3373         $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
3374         unassign_capability('moodle/site:sendmessage', $roleids['user'],
3375             context_system::instance());
3377         // Check that we can not post a message without the capability.
3378         $this->assertFalse(\core_message\api::can_post_message($user2));
3379     }
3381     /**
3382      * Tests the user can post a message when they are contact.
3383      */
3384     public function test_can_post_message_when_contact() {
3385         // Create some users.
3386         $user1 = self::getDataGenerator()->create_user();
3387         $user2 = self::getDataGenerator()->create_user();
3389         // Set as the first user.
3390         $this->setUser($user1);
3392         // Check that we can not send user2 a message.
3393         $this->assertFalse(\core_message\api::can_post_message($user2));
3395         // Add users as contacts.
3396         \core_message\api::add_contact($user1->id, $user2->id);
3398         // Check that the return result is now true.
3399         $this->assertTrue(\core_message\api::can_post_message($user2));
3400     }
3402     /**
3403      * Tests the user can't post a message if they are not a contact and the user
3404      * has requested messages only from contacts.
3405      */
3406     public function test_can_post_message_when_not_contact() {
3407         // Create some users.
3408         $user1 = self::getDataGenerator()->create_user();
3409         $user2 = self::getDataGenerator()->create_user();
3411         // Set as the first user.
3412         $this->setUser($user1);
3414         // Set the second user's preference to not receive messages from non-contacts.
3415         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2->id);
3417         // Check that we can not send user 2 a message.
3418         $this->assertFalse(\core_message\api::can_post_message($user2));
3419     }
3421     /**
3422      * Tests the user can't post a message if they are blocked.
3423      */
3424     public function test_can_post_message_when_blocked() {
3425         // Create some users.
3426         $user1 = self::getDataGenerator()->create_user();
3427         $user2 = self::getDataGenerator()->create_user();
3429         // Set the user.
3430         $this->setUser($user1);
3432         // Block the second user.
3433         \core_message\api::block_user($user1->id, $user2->id);
3435         // Check that the second user can no longer send the first user a message.
3436         $this->assertFalse(\core_message\api::can_post_message($user1, $user2));
3437     }
3439     /**
3440      * Tests the user can post a message when site-wide messaging setting is enabled,
3441      * even if they are not a contact and are not members of the same course.
3442      */
3443     public function test_can_post_message_site_messaging_setting() {
3444         // Create some users.
3445         $user1 = self::getDataGenerator()->create_user();
3446         $user2 = self::getDataGenerator()->create_user();
3448         // Set as the first user.
3449         $this->setUser($user1);
3451         // By default, user only can be messaged by contacts and members of any of his/her courses.
3452         $this->assertFalse(\core_message\api::can_post_message($user2));
3454         // Enable site-wide messagging privacy setting. The user will be able to receive messages from everybody.
3455         set_config('messagingallusers', true);
3457         // Set the second user's preference to receive messages from everybody.
3458         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_SITE, $user2->id);
3460         // Check that we can send user2 a message.
3461         $this->assertTrue(\core_message\api::can_post_message($user2));
3463         // Disable site-wide messagging privacy setting. The user will be able to receive messages from contacts
3464         // and members sharing a course with her.
3465         set_config('messagingallusers', false);
3467         // As site-wide messaging setting is disabled, the value for user2 will be changed to MESSAGE_PRIVACY_COURSEMEMBER.
3468         $this->assertFalse(\core_message\api::can_post_message($user2));
3470         // Enrol users to the same course.
3471         $course = $this->getDataGenerator()->create_course();
3472         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3473         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3474         // Check that we can send user2 a message because they are sharing a course.
3475         $this->assertTrue(\core_message\api::can_post_message($user2));
3477         // Set the second user's preference to receive messages only from contacts.
3478         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2->id);
3479         // Check that now the user2 can't be contacted because user1 is not their contact.
3480         $this->assertFalse(\core_message\api::can_post_message($user2));
3482         // Make contacts user1 and user2.
3483         \core_message\api::add_contact($user2->id, $user1->id);
3484         // Check that we can send user2 a message because they are contacts.
3485         $this->assertTrue(\core_message\api::can_post_message($user2));
3486     }
3488     /**
3489      * Tests the user with the messageanyuser capability can post a message.
3490      */
3491     public function test_can_post_message_with_messageanyuser_cap() {
3492         global $DB;
3494         // Create some users.
3495         $teacher1 = self::getDataGenerator()->create_user();
3496         $student1 = self::getDataGenerator()->create_user();
3497         $student2 = self::getDataGenerator()->create_user();
3499         // Create users not enrolled in any course.
3500         $user1 = self::getDataGenerator()->create_user();
3502         // Create a course.
3503         $course1 = $this->getDataGenerator()->create_course();
3505         // Enrol the users in the course.
3506         $this->getDataGenerator()->enrol_user($teacher1->id, $course1->id, 'editingteacher');
3507         $this->getDataGenerator()->enrol_user($student1->id, $course1->id, 'student');
3508         $this->getDataGenerator()->enrol_user($student2->id, $course1->id, 'student');
3510         // Set some student preferences to not receive messages from non-contacts.
3511         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $student1->id);
3513         // Check that we can send student1 a message because teacher has the messageanyuser cap by default.
3514         $this->assertTrue(\core_message\api::can_post_message($student1, $teacher1));
3515         // Check that the teacher can't contact user1 because it's not his teacher.
3516         $this->assertFalse(\core_message\api::can_post_message($user1, $teacher1));
3518         // Remove the messageanyuser capability from the course1 for teachers.
3519         $coursecontext = context_course::instance($course1->id);
3520         $teacherrole = $DB->get_record('role', ['shortname' => 'editingteacher']);
3521         assign_capability('moodle/site:messageanyuser', CAP_PROHIBIT, $teacherrole->id, $coursecontext->id);
3522         $coursecontext->mark_dirty();
3524         // Check that we can't send user1 a message because they are not contacts.
3525         $this->assertFalse(\core_message\api::can_post_message($student1, $teacher1));
3526         // However, teacher can message student2 because they are sharing a course.
3527         $this->assertTrue(\core_message\api::can_post_message($student2, $teacher1));
3528     }
3530     /**
3531      * Verify the expected behaviour of the can_send_message_to_conversation() method for authenticated users with default settings.
3532      */
3533     public function test_can_send_message_to_conversation_basic() {
3534         // Create some users.
3535         $user1 = self::getDataGenerator()->create_user();
3536         $user2 = self::getDataGenerator()->create_user();
3537         $user3 = self::getDataGenerator()->create_user();
3539         // Create an individual conversation between user1 and user2.
3540         $ic1 = \core_message\api::create_conversation(
3541             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3542             [
3543                 $user1->id,
3544                 $user2->id
3545             ]
3546         );
3548         // Create a group conversation between and users 1, 2 and 3.
3549         $gc1 = \core_message\api::create_conversation(
3550             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3551             [
3552                 $user1->id,
3553                 $user2->id,
3554                 $user3->id
3555             ]
3556         );
3558         // Create a self-conversation for user1.
3559         $sc1 = \core_message\api::create_conversation(
3560             \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF,
3561             [$user1->id]
3562         );
3564         // For group conversations, there are no user privacy checks, so only membership in the conversation is needed.
3565         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3567         // For self conversations, there are no user privacy checks, so only membership in the conversation is needed.
3568         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $sc1->id));
3570         // For individual conversations, the default privacy setting of 'only contacts and course members' applies.
3571         // Users are not in the same course, nor are they contacts, so messages cannot be sent.
3572         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3574         // Enrol the users into the same course.
3575         $course = $this->getDataGenerator()->create_course();
3576         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3577         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3579         // After enrolling users to the course, they should be able to message them with the default privacy setting.
3580         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3581     }
3583     /**
3584      * Verify the behaviour of can_send_message_to_conversation() for authenticated users without the sendmessage capability.
3585      */
3586     public function test_can_send_message_to_conversation_sendmessage_cap() {
3587         global $DB;
3589         $user1 = self::getDataGenerator()->create_user();
3590         $user2 = self::getDataGenerator()->create_user();
3591         $user3 = self::getDataGenerator()->create_user();
3593         // Enrol the users into the same course.
3594         $course = $this->getDataGenerator()->create_course();
3595         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3596         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3597         $this->getDataGenerator()->enrol_user($user3->id, $course->id);
3599         // Create an individual conversation between user1 and user2.
3600         $ic1 = \core_message\api::create_conversation(
3601             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3602             [
3603                 $user1->id,
3604                 $user2->id
3605             ]
3606         );
3608         // Group conversation between and users 1, 2 and 3.
3609         $gc1 = \core_message\api::create_conversation(
3610             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3611             [
3612                 $user1->id,
3613                 $user2->id,
3614                 $user3->id
3615             ]
3616         );
3618         // Default settings - user1 can send a message to both conversations.
3619         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3620         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3622         // Remove the capability to send a message.
3623         $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
3624         unassign_capability('moodle/site:sendmessage', $roleids['user'], context_system::instance());
3626         // Verify that a user cannot send a message to either an individual or a group conversation.
3627         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3628         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3629     }
3631     /**
3632      * Verify the behaviour of can_send_message_to_conversation() for authenticated users without the messageanyuser capability.
3633      */
3634     public function test_can_send_message_to_conversation_messageanyuser_cap() {
3635         global $DB;
3637         $user1 = self::getDataGenerator()->create_user();
3638         $user2 = self::getDataGenerator()->create_user();
3639         $user3 = self::getDataGenerator()->create_user();
3641         // Enrol the users into the same course.
3642         $course = $this->getDataGenerator()->create_course();
3643         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3644         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3645         $this->getDataGenerator()->enrol_user($user3->id, $course->id);
3647         // Create an individual conversation between user1 and user2.
3648         $ic1 = \core_message\api::create_conversation(
3649             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3650             [
3651                 $user1->id,
3652                 $user2->id
3653             ]
3654         );
3656         // Group conversation between and users 1, 2 and 3.
3657         $gc1 = \core_message\api::create_conversation(
3658             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3659             [
3660                 $user1->id,
3661                 $user2->id,
3662                 $user3->id
3663             ]
3664         );
3666         // Update the message preference for user2, so they can only be messaged by contacts.
3667         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2->id);
3669         // Verify that the user cannot be contacted in the individual conversation and that groups are unaffected.
3670         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3671         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3673         // Assign the 'messageanyuser' capability to user1 at system context.
3674         $systemcontext = context_system::instance();
3675         $authenticateduser = $DB->get_record('role', ['shortname' => 'user']);
3676         assign_capability('moodle/site:messageanyuser', CAP_ALLOW, $authenticateduser->id, $systemcontext->id);
3678         // Check that user1 can now message user2 due to the capability, and that group conversations is again unaffected.
3679         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3680         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3681     }
3683     /**
3684      * Test verifying that users cannot send messages to conversations they are not a part of.
3685      */
3686     public function test_can_post_message_to_conversation_non_member() {
3687         // Create some users.
3688         $user1 = self::getDataGenerator()->create_user();
3689         $user2 = self::getDataGenerator()->create_user();
3690         $user3 = self::getDataGenerator()->create_user();
3691         $user4 = self::getDataGenerator()->create_user();
3693         // Enrol the users into the same course.
3694         $course = $this->getDataGenerator()->create_course();
3695         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3696         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3697         $this->getDataGenerator()->enrol_user($user3->id, $course->id);
3698         $this->getDataGenerator()->enrol_user($user4->id, $course->id);
3700         // Create an individual conversation between user1 and user2.
3701         $ic1 = \core_message\api::create_conversation(
3702             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3703             [
3704                 $user1->id,
3705                 $user2->id
3706             ]
3707         );
3709         // Create a group conversation between and users 1, 2 and 3.
3710         $gc1 = \core_message\api::create_conversation(
3711             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3712             [
3713                 $user1->id,
3714                 $user2->id,
3715                 $user3->id
3716             ]
3717         );
3719         // Create a self-conversation for user1.
3720         $sc1 = \core_message\api::create_conversation(
3721             \core_message\api::MESSAGE_CONVERSATION_TYPE_SELF,
3722             [$user1->id]
3723         );
3725         // Verify, non members cannot send a message.
3726         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user4->id, $gc1->id));
3727         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user4->id, $ic1->id));
3728         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user4->id, $sc1->id));
3729     }
3731     /**
3732      * Test verifying the behaviour of the can_send_message_to_conversation method when privacy is set to contacts only.
3733      */
3734     public function test_can_send_message_to_conversation_privacy_contacts_only() {
3735         // Create some users.
3736         $user1 = self::getDataGenerator()->create_user();
3737         $user2 = self::getDataGenerator()->create_user();
3738         $user3 = self::getDataGenerator()->create_user();
3740         // Create an individual conversation between user1 and user2.
3741         $ic1 = \core_message\api::create_conversation(
3742             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3743             [
3744                 $user1->id,
3745                 $user2->id
3746             ]
3747         );
3749         // Create a group conversation between and users 1, 2 and 3.
3750         $gc1 = \core_message\api::create_conversation(
3751             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3752             [
3753                 $user1->id,
3754                 $user2->id,
3755                 $user3->id
3756             ]
3757         );
3759         // Set the message privacy preference to 'contacts only' for user 2.
3760         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2->id);
3762         // Verify that user1 cannot send a message to the individual conversation, but that the group conversation is unaffected.
3763         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3764         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3766         // Now, simulate a contact request (and approval) between user1 and user2.
3767         \core_message\api::create_contact_request($user1->id, $user2->id);
3768         \core_message\api::confirm_contact_request($user1->id, $user2->id);
3770         // Verify user1 can now message user2 again via their individual conversation.
3771         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3772     }
3774     /**
3775      * Test verifying the behaviour of the can_send_message_to_conversation method when privacy is set to contacts / course members.
3776      */
3777     public function test_can_send_message_to_conversation_privacy_contacts_course() {
3778         // Create some users.
3779         $user1 = self::getDataGenerator()->create_user();
3780         $user2 = self::getDataGenerator()->create_user();
3781         $user3 = self::getDataGenerator()->create_user();
3783         // Set the message privacy preference to 'contacts + course members' for user 2.
3784         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_COURSEMEMBER, $user2->id);
3786         // Create an individual conversation between user1 and user2.
3787         $ic1 = \core_message\api::create_conversation(
3788             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3789             [
3790                 $user1->id,
3791                 $user2->id
3792             ]
3793         );
3795         // Create a group conversation between and users 1, 2 and 3.
3796         $gc1 = \core_message\api::create_conversation(
3797             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3798             [
3799                 $user1->id,
3800                 $user2->id,
3801                 $user3->id
3802             ]
3803         );
3805         // Verify that users in a group conversation can message one another (i.e. privacy controls ignored).
3806         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $gc1->id));
3808         // Verify that user1 can not message user2 unless they are either contacts, or share a course.
3809         $this->assertFalse(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3811         // Enrol the users into the same course.
3812         $course = $this->getDataGenerator()->create_course();
3813         $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3814         $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3815         $this->getDataGenerator()->enrol_user($user3->id, $course->id);
3817         // Verify that user1 can send a message to user2, based on the shared course, without being a contact.
3818         $this->assertFalse(\core_message\api::is_contact($user1->id, $user2->id));
3819         $this->assertTrue(\core_message\api::can_send_message_to_conversation($user1->id, $ic1->id));
3820     }
3822     /**
3823      * Test verifying the behaviour of the can_send_message_to_conversation method when privacy is set to any user.
3824      */
3825     public function test_can_send_message_to_conversation_privacy_sitewide() {
3826         // Create some users.
3827         $user1 = self::getDataGenerator()->create_user();
3828         $user2 = self::getDataGenerator()->create_user();
3829         $user3 = self::getDataGenerator()->create_user();
3831         // Create an individual conversation between user1 and user2.
3832         $ic1 = \core_message\api::create_conversation(
3833             \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3834             [
3835                 $user1->id,
3836                 $user2->id
3837             ]
3838         );