Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]

   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/>.
  16  
  17  namespace core_message;
  18  
  19  use core_message\tests\helper as testhelper;
  20  
  21  defined('MOODLE_INTERNAL') || die();
  22  
  23  global $CFG;
  24  
  25  require_once($CFG->dirroot . '/message/tests/messagelib_test.php');
  26  
  27  /**
  28   * Test message API.
  29   *
  30   * @package core_message
  31   * @category test
  32   * @copyright 2016 Mark Nelson <markn@moodle.com>
  33   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  34   */
  35  class api_test extends messagelib_test {
  36  
  37      public function test_mark_all_read_for_user_touser() {
  38          $sender = $this->getDataGenerator()->create_user(array('firstname' => 'Test1', 'lastname' => 'User1'));
  39          $recipient = $this->getDataGenerator()->create_user(array('firstname' => 'Test2', 'lastname' => 'User2'));
  40  
  41          $this->send_fake_message($sender, $recipient, 'Notification', 1);
  42          $this->send_fake_message($sender, $recipient, 'Notification', 1);
  43          $this->send_fake_message($sender, $recipient, 'Notification', 1);
  44          $this->send_fake_message($sender, $recipient);
  45          $this->send_fake_message($sender, $recipient);
  46          $this->send_fake_message($sender, $recipient);
  47  
  48          api::mark_all_notifications_as_read($recipient->id);
  49          api::mark_all_messages_as_read($recipient->id);
  50  
  51          $this->assertEquals(message_count_unread_messages($recipient), 0);
  52          $this->assertDebuggingCalled();
  53      }
  54  
  55      public function test_mark_all_read_for_user_touser_with_fromuser() {
  56          $sender1 = $this->getDataGenerator()->create_user(array('firstname' => 'Test1', 'lastname' => 'User1'));
  57          $sender2 = $this->getDataGenerator()->create_user(array('firstname' => 'Test3', 'lastname' => 'User3'));
  58          $recipient = $this->getDataGenerator()->create_user(array('firstname' => 'Test2', 'lastname' => 'User2'));
  59  
  60          $this->send_fake_message($sender1, $recipient, 'Notification', 1);
  61          $this->send_fake_message($sender1, $recipient, 'Notification', 1);
  62          $this->send_fake_message($sender1, $recipient, 'Notification', 1);
  63          $this->send_fake_message($sender1, $recipient);
  64          $this->send_fake_message($sender1, $recipient);
  65          $this->send_fake_message($sender1, $recipient);
  66          $this->send_fake_message($sender2, $recipient, 'Notification', 1);
  67          $this->send_fake_message($sender2, $recipient, 'Notification', 1);
  68          $this->send_fake_message($sender2, $recipient, 'Notification', 1);
  69          $this->send_fake_message($sender2, $recipient);
  70          $this->send_fake_message($sender2, $recipient);
  71          $this->send_fake_message($sender2, $recipient);
  72  
  73          api::mark_all_notifications_as_read($recipient->id, $sender1->id);
  74          $conversationid = api::get_conversation_between_users([$recipient->id, $sender1->id]);
  75          api::mark_all_messages_as_read($recipient->id, $conversationid);
  76  
  77          $this->assertEquals(message_count_unread_messages($recipient), 3);
  78          $this->assertDebuggingCalled();
  79      }
  80  
  81      public function test_mark_all_read_for_user_touser_with_type() {
  82          $sender = $this->getDataGenerator()->create_user(array('firstname' => 'Test1', 'lastname' => 'User1'));
  83          $recipient = $this->getDataGenerator()->create_user(array('firstname' => 'Test2', 'lastname' => 'User2'));
  84  
  85          $this->send_fake_message($sender, $recipient, 'Notification', 1);
  86          $this->send_fake_message($sender, $recipient, 'Notification', 1);
  87          $this->send_fake_message($sender, $recipient, 'Notification', 1);
  88          $this->send_fake_message($sender, $recipient);
  89          $this->send_fake_message($sender, $recipient);
  90          $this->send_fake_message($sender, $recipient);
  91  
  92          api::mark_all_notifications_as_read($recipient->id);
  93          $this->assertEquals(message_count_unread_messages($recipient), 3);
  94          $this->assertDebuggingCalled();
  95  
  96          api::mark_all_messages_as_read($recipient->id);
  97          $this->assertEquals(message_count_unread_messages($recipient), 0);
  98          $this->assertDebuggingCalled();
  99      }
 100  
 101      /**
 102       * Test count_blocked_users.
 103       */
 104      public function test_count_blocked_users() {
 105          global $USER;
 106  
 107          // Set this user as the admin.
 108          $this->setAdminUser();
 109  
 110          // Create user to add to the admin's block list.
 111          $user1 = $this->getDataGenerator()->create_user();
 112          $user2 = $this->getDataGenerator()->create_user();
 113  
 114          $this->assertEquals(0, api::count_blocked_users());
 115  
 116          // Add 1 blocked user to admin's blocked user list.
 117          api::block_user($USER->id, $user1->id);
 118  
 119          $this->assertEquals(0, api::count_blocked_users($user1));
 120          $this->assertEquals(1, api::count_blocked_users());
 121      }
 122  
 123      /**
 124       * Tests searching for users when site-wide messaging is disabled.
 125       *
 126       * This test verifies that any contacts are returned, as well as any non-contacts whose profile we can view.
 127       * If checks this by placing some users in the same course, where default caps would permit a user to view another user's
 128       * profile.
 129       */
 130      public function test_message_search_users_messagingallusers_disabled() {
 131          global $DB;
 132          $this->resetAfterTest();
 133  
 134          // Create some users.
 135          $users = [];
 136          foreach (range(1, 8) as $i) {
 137              $user = new \stdClass();
 138              $user->firstname = ($i == 4) ? 'User' : 'User search'; // Ensure the fourth user won't match the search term.
 139              $user->lastname = $i;
 140              $user = $this->getDataGenerator()->create_user($user);
 141              $users[$i] = $user;
 142          }
 143  
 144          // Enrol a few users in the same course, but leave them as non-contacts.
 145          $course1 = $this->getDataGenerator()->create_course();
 146          $course2 = $this->getDataGenerator()->create_course();
 147  
 148          $this->setAdminUser();
 149          $this->getDataGenerator()->enrol_user($users[1]->id, $course1->id);
 150          $this->getDataGenerator()->enrol_user($users[6]->id, $course1->id);
 151          $this->getDataGenerator()->enrol_user($users[7]->id, $course1->id);
 152  
 153          // Add some other users as contacts.
 154          api::add_contact($users[1]->id, $users[2]->id);
 155          api::add_contact($users[3]->id, $users[1]->id);
 156          api::add_contact($users[1]->id, $users[4]->id);
 157  
 158          // Enrol a user as a teacher in the course, and make the teacher role a course contact role.
 159          $this->getDataGenerator()->enrol_user($users[8]->id, $course2->id, 'editingteacher');
 160          $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
 161          set_config('coursecontact', $teacherrole->id);
 162  
 163          // Create individual conversations between some users, one contact and one non-contact.
 164          $ic1 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
 165              [$users[1]->id, $users[2]->id]);
 166          $ic2 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
 167              [$users[6]->id, $users[1]->id]);
 168  
 169          // Create a group conversation between 4 users, including a contact and a non-contact.
 170          $gc1 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_GROUP,
 171              [$users[1]->id, $users[2]->id, $users[4]->id, $users[7]->id], 'Project chat');
 172  
 173          // Set as the user performing the search.
 174          $this->setUser($users[1]);
 175  
 176          // Perform a search with $CFG->messagingallusers disabled.
 177          set_config('messagingallusers', 0);
 178          $result = api::message_search_users($users[1]->id, 'search');
 179  
 180          // Confirm that we returns contacts and non-contacts.
 181          $this->assertArrayHasKey(0, $result);
 182          $this->assertArrayHasKey(1, $result);
 183          $contacts = $result[0];
 184          $noncontacts = $result[1];
 185  
 186          // Check that we retrieved the correct contacts.
 187          $this->assertCount(2, $contacts);
 188          $this->assertEquals($users[2]->id, $contacts[0]->id);
 189          $this->assertEquals($users[3]->id, $contacts[1]->id);
 190  
 191          // Verify the correct conversations were returned for the contacts.
 192          $this->assertCount(2, $contacts[0]->conversations);
 193          $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_GROUP, $contacts[0]->conversations[$gc1->id]->type);
 194          $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $contacts[0]->conversations[$ic1->id]->type);
 195  
 196          $this->assertCount(0, $contacts[1]->conversations);
 197  
 198          // Check that we retrieved the correct non-contacts.
 199          // When site wide messaging is disabled, we expect to see only those users who we share a course with and whose profiles
 200          // are visible in that course. This excludes users like course contacts.
 201          $this->assertCount(3, $noncontacts);
 202          // Self-conversation first.
 203          $this->assertEquals($users[1]->id, $noncontacts[0]->id);
 204          $this->assertEquals($users[6]->id, $noncontacts[1]->id);
 205          $this->assertEquals($users[7]->id, $noncontacts[2]->id);
 206  
 207          // Verify the correct conversations were returned for the non-contacts.
 208          $this->assertCount(1, $noncontacts[1]->conversations);
 209          $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
 210              $noncontacts[1]->conversations[$ic2->id]->type);
 211  
 212          $this->assertCount(1, $noncontacts[2]->conversations);
 213          $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_GROUP, $noncontacts[2]->conversations[$gc1->id]->type);
 214      }
 215  
 216      /**
 217       * Tests searching for users when site-wide messaging is enabled.
 218       *
 219       * This test verifies that any contacts are returned, as well as any non-contacts,
 220       * provided the searching user can view their profile.
 221       */
 222      public function test_message_search_users_messagingallusers_enabled() {
 223          global $DB;
 224          $this->resetAfterTest();
 225  
 226          // Create some users.
 227          $users = [];
 228          foreach (range(1, 9) as $i) {
 229              $user = new \stdClass();
 230              $user->firstname = ($i == 4) ? 'User' : 'User search'; // Ensure the fourth user won't match the search term.
 231              $user->lastname = $i;
 232              $user = $this->getDataGenerator()->create_user($user);
 233              $users[$i] = $user;
 234          }
 235  
 236          $course1 = $this->getDataGenerator()->create_course();
 237          $coursecontext = \context_course::instance($course1->id);
 238  
 239          // Enrol a few users in the same course, but leave them as non-contacts.
 240          $this->setAdminUser();
 241          $this->getDataGenerator()->enrol_user($users[1]->id, $course1->id, 'student');
 242          $this->getDataGenerator()->enrol_user($users[6]->id, $course1->id, 'student');
 243          $this->getDataGenerator()->enrol_user($users[7]->id, $course1->id, 'student');
 244  
 245          // Add some other users as contacts.
 246          api::add_contact($users[1]->id, $users[2]->id);
 247          api::add_contact($users[3]->id, $users[1]->id);
 248          api::add_contact($users[1]->id, $users[4]->id);
 249  
 250          // Enrol a user as a teacher in the course, and make the teacher role a course contact role.
 251          $this->getDataGenerator()->enrol_user($users[9]->id, $course1->id, 'editingteacher');
 252          $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
 253          set_config('coursecontact', $teacherrole->id);
 254  
 255          // Get self-conversation.
 256          $selfconversation = api::get_self_conversation($users[1]->id);
 257  
 258          // Create individual conversations between some users, one contact and one non-contact.
 259          $ic1 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
 260              [$users[1]->id, $users[2]->id]);
 261          $ic2 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
 262              [$users[6]->id, $users[1]->id]);
 263  
 264          // Create a group conversation between 5 users, including a contact and a non-contact, and a user NOT in a shared course.
 265          $gc1 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_GROUP,
 266              [$users[1]->id, $users[2]->id, $users[4]->id, $users[7]->id, $users[8]->id], 'Project chat');
 267  
 268          // Set as the user performing the search.
 269          $this->setUser($users[1]);
 270  
 271          // Perform a search with $CFG->messagingallusers enabled.
 272          set_config('messagingallusers', 1);
 273          $result = api::message_search_users($users[1]->id, 'search');
 274  
 275          // Confirm that we returns contacts and non-contacts.
 276          $this->assertArrayHasKey(0, $result);
 277          $this->assertArrayHasKey(1, $result);
 278          $contacts = $result[0];
 279          $noncontacts = $result[1];
 280  
 281          // Check that we retrieved the correct contacts.
 282          $this->assertCount(2, $contacts);
 283          $this->assertEquals($users[2]->id, $contacts[0]->id);
 284          $this->assertEquals($users[3]->id, $contacts[1]->id);
 285  
 286          // Verify the correct conversations were returned for the contacts.
 287          $this->assertCount(2, $contacts[0]->conversations);
 288          $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_GROUP, $contacts[0]->conversations[$gc1->id]->type);
 289          $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $contacts[0]->conversations[$ic1->id]->type);
 290  
 291          $this->assertCount(0, $contacts[1]->conversations);
 292  
 293          // Check that we retrieved the correct non-contacts.
 294          // If site wide messaging is enabled, we expect to only be able to search for users whose profiles we can view.
 295          // In this case, as a student, that's the course contact for course2 and those noncontacts sharing a course with user1.
 296          // Consider first conversations is self-conversation.
 297          $this->assertCount(4, $noncontacts);
 298          $this->assertEquals($users[1]->id, $noncontacts[0]->id);
 299          $this->assertEquals($users[6]->id, $noncontacts[1]->id);
 300          $this->assertEquals($users[7]->id, $noncontacts[2]->id);
 301          $this->assertEquals($users[9]->id, $noncontacts[3]->id);
 302  
 303          $this->assertCount(1, $noncontacts[1]->conversations);
 304          $this->assertCount(1, $noncontacts[2]->conversations);
 305          $this->assertCount(0, $noncontacts[3]->conversations);
 306  
 307          // Verify the correct conversations were returned for the non-contacts.
 308          $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_SELF,
 309              $noncontacts[0]->conversations[$selfconversation->id]->type);
 310  
 311          $this->assertCount(1, $noncontacts[1]->conversations);
 312          $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
 313              $noncontacts[1]->conversations[$ic2->id]->type);
 314  
 315          $this->assertCount(1, $noncontacts[2]->conversations);
 316          $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_GROUP, $noncontacts[2]->conversations[$gc1->id]->type);
 317  
 318          $this->assertCount(0, $noncontacts[3]->conversations);
 319      }
 320  
 321      /**
 322       * Verify searching for users find themselves when they have self-conversations.
 323       */
 324      public function test_message_search_users_self_conversations() {
 325          $this->resetAfterTest();
 326  
 327          // Create some users.
 328          $user1 = new \stdClass();
 329          $user1->firstname = 'User';
 330          $user1->lastname = 'One';
 331          $user1 = $this->getDataGenerator()->create_user($user1);
 332          $user2 = new \stdClass();
 333          $user2->firstname = 'User';
 334          $user2->lastname = 'Two';
 335          $user2 = $this->getDataGenerator()->create_user($user2);
 336  
 337          // Get self-conversation for user1.
 338          $sc1 = api::get_self_conversation($user1->id);
 339          testhelper::send_fake_message_to_conversation($user1, $sc1->id, 'Hi myself!');
 340  
 341          // Perform a search as user1.
 342          $this->setUser($user1);
 343          $result = api::message_search_users($user1->id, 'One');
 344  
 345          // Check user1 is found as non-contacts.
 346          $this->assertCount(0, $result[0]);
 347          $this->assertCount(1, $result[1]);
 348      }
 349  
 350      /**
 351       * Verify searching for users works even if no matching users from either contacts, or non-contacts can be found.
 352       */
 353      public function test_message_search_users_with_empty_result() {
 354          $this->resetAfterTest();
 355  
 356          // Create some users, but make sure neither will match the search term.
 357          $user1 = new \stdClass();
 358          $user1->firstname = 'User';
 359          $user1->lastname = 'One';
 360          $user1 = $this->getDataGenerator()->create_user($user1);
 361          $user2 = new \stdClass();
 362          $user2->firstname = 'User';
 363          $user2->lastname = 'Two';
 364          $user2 = $this->getDataGenerator()->create_user($user2);
 365  
 366          // Perform a search as user1.
 367          $this->setUser($user1);
 368          $result = api::message_search_users($user1->id, 'search');
 369  
 370          // Check results are empty.
 371          $this->assertCount(0, $result[0]);
 372          $this->assertCount(0, $result[1]);
 373      }
 374  
 375      /**
 376       * Test verifying that limits and offsets work for both the contacts and non-contacts return data.
 377       */
 378      public function test_message_search_users_limit_offset() {
 379          $this->resetAfterTest();
 380  
 381          // Create 20 users.
 382          $users = [];
 383          foreach (range(1, 20) as $i) {
 384              $user = new \stdClass();
 385              $user->firstname = "User search";
 386              $user->lastname = $i;
 387              $user = $this->getDataGenerator()->create_user($user);
 388              $users[$i] = $user;
 389          }
 390  
 391          // Enrol the first 9 users in the same course, but leave them as non-contacts.
 392          $this->setAdminUser();
 393          $course1 = $this->getDataGenerator()->create_course();
 394          foreach (range(1, 8) as $i) {
 395              $this->getDataGenerator()->enrol_user($users[$i]->id, $course1->id);
 396          }
 397  
 398          // Add 5 users, starting at the 11th user, as contacts for user1.
 399          foreach (range(11, 15) as $i) {
 400              api::add_contact($users[1]->id, $users[$i]->id);
 401          }
 402  
 403          // Set as the user performing the search.
 404          $this->setUser($users[1]);
 405  
 406          // Search using a limit of 3.
 407          // This tests the case where we have more results than the limit for both contacts and non-contacts.
 408          $result = api::message_search_users($users[1]->id, 'search', 0, 3);
 409          $contacts = $result[0];
 410          $noncontacts = $result[1];
 411  
 412          // Check that we retrieved the correct contacts.
 413          $this->assertCount(3, $contacts);
 414          $this->assertEquals($users[11]->id, $contacts[0]->id);
 415          $this->assertEquals($users[12]->id, $contacts[1]->id);
 416          $this->assertEquals($users[13]->id, $contacts[2]->id);
 417  
 418          // Check that we retrieved the correct non-contacts.
 419          // Consider first conversations is self-conversation.
 420          $this->assertCount(3, $noncontacts);
 421          $this->assertEquals($users[1]->id, $noncontacts[0]->id);
 422          $this->assertEquals($users[2]->id, $noncontacts[1]->id);
 423          $this->assertEquals($users[3]->id, $noncontacts[2]->id);
 424  
 425          // Now, offset to get the next batch of results.
 426          // We expect to see 2 contacts, and 3 non-contacts.
 427          $result = api::message_search_users($users[1]->id, 'search', 3, 3);
 428          $contacts = $result[0];
 429          $noncontacts = $result[1];
 430          $this->assertCount(2, $contacts);
 431          $this->assertEquals($users[14]->id, $contacts[0]->id);
 432          $this->assertEquals($users[15]->id, $contacts[1]->id);
 433  
 434          $this->assertCount(3, $noncontacts);
 435          $this->assertEquals($users[4]->id, $noncontacts[0]->id);
 436          $this->assertEquals($users[5]->id, $noncontacts[1]->id);
 437          $this->assertEquals($users[6]->id, $noncontacts[2]->id);
 438  
 439          // Now, offset to get the next batch of results.
 440          // We expect to see 0 contacts, and 2 non-contacts.
 441          $result = api::message_search_users($users[1]->id, 'search', 6, 3);
 442          $contacts = $result[0];
 443          $noncontacts = $result[1];
 444          $this->assertCount(0, $contacts);
 445  
 446          $this->assertCount(2, $noncontacts);
 447          $this->assertEquals($users[7]->id, $noncontacts[0]->id);
 448          $this->assertEquals($users[8]->id, $noncontacts[1]->id);
 449      }
 450  
 451      /**
 452       * Tests searching users as a user having the 'moodle/user:viewdetails' capability.
 453       */
 454      public function test_message_search_users_with_cap() {
 455          $this->resetAfterTest();
 456          global $DB;
 457  
 458          // Create some users.
 459          $users = [];
 460          foreach (range(1, 8) as $i) {
 461              $user = new \stdClass();
 462              $user->firstname = ($i == 4) ? 'User' : 'User search'; // Ensure the fourth user won't match the search term.
 463              $user->lastname = $i;
 464              $user = $this->getDataGenerator()->create_user($user);
 465              $users[$i] = $user;
 466          }
 467  
 468          // Enrol a few users in the same course, but leave them as non-contacts.
 469          $course1 = $this->getDataGenerator()->create_course();
 470          $this->setAdminUser();
 471          $this->getDataGenerator()->enrol_user($users[1]->id, $course1->id);
 472          $this->getDataGenerator()->enrol_user($users[6]->id, $course1->id);
 473          $this->getDataGenerator()->enrol_user($users[7]->id, $course1->id);
 474  
 475          // Add some other users as contacts.
 476          api::add_contact($users[1]->id, $users[2]->id);
 477          api::add_contact($users[3]->id, $users[1]->id);
 478          api::add_contact($users[1]->id, $users[4]->id);
 479  
 480          // Set as the user performing the search.
 481          $this->setUser($users[1]);
 482  
 483          // Grant the authenticated user role the capability 'user:viewdetails' at site context.
 484          $authenticatedrole = $DB->get_record('role', ['shortname' => 'user'], '*', MUST_EXIST);
 485          assign_capability('moodle/user:viewdetails', CAP_ALLOW, $authenticatedrole->id, \context_system::instance());
 486  
 487          // Perform a search with $CFG->messagingallusers disabled.
 488          set_config('messagingallusers', 0);
 489          $result = api::message_search_users($users[1]->id, 'search');
 490          $contacts = $result[0];
 491          $noncontacts = $result[1];
 492  
 493          // Check that we retrieved the correct contacts.
 494          $this->assertCount(2, $contacts);
 495          $this->assertEquals($users[2]->id, $contacts[0]->id);
 496          $this->assertEquals($users[3]->id, $contacts[1]->id);
 497  
 498          // Check that we retrieved the correct non-contacts.
 499          // Site-wide messaging is disabled, so we expect to be able to search for any users whose profiles we can view.
 500          // Consider first conversations is self-conversation.
 501          $this->assertCount(3, $noncontacts);
 502          $this->assertEquals($users[1]->id, $noncontacts[0]->id);
 503          $this->assertEquals($users[6]->id, $noncontacts[1]->id);
 504          $this->assertEquals($users[7]->id, $noncontacts[2]->id);
 505      }
 506  
 507      /**
 508       * Tests searching users with messaging disabled.
 509       */
 510      public function test_message_search_users_messaging_disabled() {
 511          $this->resetAfterTest();
 512  
 513          // Create a user.
 514          $user = $this->getDataGenerator()->create_user();
 515  
 516          // Disable messaging.
 517          set_config('messaging', 0);
 518  
 519          // Ensure an exception is thrown.
 520          $this->expectException('moodle_exception');
 521          api::message_search_users($user->id, 'User');
 522      }
 523  
 524      /**
 525       * Tests getting conversations between 2 users.
 526       */
 527      public function test_get_conversations_between_users() {
 528          // Create some users.
 529          $user1 = new \stdClass();
 530          $user1->firstname = 'User';
 531          $user1->lastname = 'One';
 532          $user1 = self::getDataGenerator()->create_user($user1);
 533  
 534          $user2 = new \stdClass();
 535          $user2->firstname = 'User';
 536          $user2->lastname = 'Two';
 537          $user2 = self::getDataGenerator()->create_user($user2);
 538  
 539          $user3 = new \stdClass();
 540          $user3->firstname = 'User search';
 541          $user3->lastname = 'Three';
 542          $user3 = self::getDataGenerator()->create_user($user3);
 543  
 544          $user4 = new \stdClass();
 545          $user4->firstname = 'User';
 546          $user4->lastname = 'Four';
 547          $user4 = self::getDataGenerator()->create_user($user4);
 548  
 549          $user5 = new \stdClass();
 550          $user5->firstname = 'User';
 551          $user5->lastname = 'Five';
 552          $user5 = self::getDataGenerator()->create_user($user5);
 553  
 554          $user6 = new \stdClass();
 555          $user6->firstname = 'User search';
 556          $user6->lastname = 'Six';
 557          $user6 = self::getDataGenerator()->create_user($user6);
 558  
 559          // Add some users as contacts.
 560          api::add_contact($user1->id, $user2->id);
 561          api::add_contact($user6->id, $user1->id);
 562  
 563          // Create private conversations with some users.
 564          api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
 565              array($user1->id, $user2->id));
 566          api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
 567              array($user3->id, $user1->id));
 568  
 569          // Create a group conversation with users.
 570          api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_GROUP,
 571              array($user1->id, $user2->id, $user3->id, $user4->id),
 572              'Project chat');
 573  
 574          // Check that we retrieved the correct conversations.
 575          $this->assertCount(2, api::get_conversations_between_users($user1->id, $user2->id));
 576          $this->assertCount(2, api::get_conversations_between_users($user2->id, $user1->id));
 577          $this->assertCount(2, api::get_conversations_between_users($user1->id, $user3->id));
 578          $this->assertCount(2, api::get_conversations_between_users($user3->id, $user1->id));
 579          $this->assertCount(1, api::get_conversations_between_users($user1->id, $user4->id));
 580          $this->assertCount(1, api::get_conversations_between_users($user4->id, $user1->id));
 581          $this->assertCount(0, api::get_conversations_between_users($user1->id, $user5->id));
 582          $this->assertCount(0, api::get_conversations_between_users($user5->id, $user1->id));
 583          $this->assertCount(0, api::get_conversations_between_users($user1->id, $user6->id));
 584          $this->assertCount(0, api::get_conversations_between_users($user6->id, $user1->id));
 585      }
 586  
 587      /**
 588       * Tests getting self-conversations.
 589       */
 590      public function test_get_self_conversation() {
 591          // Create some users.
 592          $user1 = new \stdClass();
 593          $user1->firstname = 'User';
 594          $user1->lastname = 'One';
 595          $user1 = self::getDataGenerator()->create_user($user1);
 596  
 597          $user2 = new \stdClass();
 598          $user2->firstname = 'User';
 599          $user2->lastname = 'Two';
 600          $user2 = self::getDataGenerator()->create_user($user2);
 601  
 602          $user3 = new \stdClass();
 603          $user3->firstname = 'User search';
 604          $user3->lastname = 'Three';
 605          $user3 = self::getDataGenerator()->create_user($user3);
 606  
 607          // Add some users as contacts.
 608          api::add_contact($user1->id, $user2->id);
 609          api::add_contact($user3->id, $user1->id);
 610  
 611          // Create private conversations with some users.
 612          api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
 613              array($user1->id, $user2->id));
 614          api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
 615              array($user3->id, $user1->id));
 616  
 617          // Create a group conversation with users.
 618          $gc = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_GROUP,
 619              array($user1->id, $user2->id, $user3->id),
 620              'Project chat');
 621  
 622          // Get self-conversations.
 623          $rsc1 = api::get_self_conversation($user1->id);
 624          $rsc2 = api::get_self_conversation($user2->id);
 625          $rsc3 = api::get_self_conversation($user3->id);
 626  
 627          // Send message to self-conversation.
 628          testhelper::send_fake_message_to_conversation($user1, $rsc1->id, 'Message to myself!');
 629  
 630          // Check that we retrieved the correct conversations.
 631          $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_SELF, $rsc1->type);
 632          $members = api::get_conversation_members($user1->id, $rsc1->id);
 633          $this->assertCount(1, $members);
 634          $member = reset($members);
 635          $this->assertEquals($user1->id, $member->id);
 636  
 637          $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_SELF, $rsc2->type);
 638          $members = api::get_conversation_members($user2->id, $rsc2->id);
 639          $this->assertCount(1, $members);
 640          $member = reset($members);
 641          $this->assertEquals($user2->id, $member->id);
 642  
 643          api::delete_all_conversation_data($rsc3->id);
 644          $selfconversation = api::get_self_conversation($user3->id);
 645          $members = api::get_conversation_members($user1->id, $selfconversation->id);
 646          $this->assertCount(1, $members);
 647      }
 648  
 649      /**
 650       * Tests searching messages.
 651       */
 652      public function test_search_messages() {
 653          $this->resetAfterTest();
 654  
 655          // Create some users.
 656          $user1 = self::getDataGenerator()->create_user();
 657          $user2 = self::getDataGenerator()->create_user();
 658          $user3 = self::getDataGenerator()->create_user();
 659  
 660          // The person doing the search.
 661          $this->setUser($user1);
 662  
 663          // Get self-conversation.
 664          $sc = api::get_self_conversation($user1->id);
 665  
 666          // Create group conversation.
 667          $gc = api::create_conversation(
 668              api::MESSAGE_CONVERSATION_TYPE_GROUP,
 669              [$user1->id, $user2->id, $user3->id]
 670          );
 671  
 672          // Send some messages back and forth.
 673          $time = 1;
 674          testhelper::send_fake_message_to_conversation($user1, $sc->id, 'Test message to self!', $time);
 675          testhelper::send_fake_message_to_conversation($user1, $gc->id, 'My hero!', $time + 1);
 676          $this->send_fake_message($user3, $user1, 'Don\'t block me.', 0, $time + 2);
 677          $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 3);
 678          $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 4);
 679          $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 5);
 680          $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 6);
 681  
 682          $convid = api::get_conversation_between_users([$user1->id, $user2->id]);
 683          $conv2id = api::get_conversation_between_users([$user1->id, $user3->id]);
 684  
 685          // Block user 3.
 686          api::block_user($user1->id, $user3->id);
 687  
 688          // Perform a search.
 689          $messages = api::search_messages($user1->id, 'o');
 690  
 691          // Confirm the data is correct.
 692          $this->assertEquals(5, count($messages));
 693          $message1 = $messages[0];
 694          $message2 = $messages[1];
 695          $message3 = $messages[2];
 696          $message4 = $messages[3];
 697          $message5 = $messages[4];
 698  
 699          $this->assertEquals($user2->id, $message1->userid);
 700          $this->assertEquals($user2->id, $message1->useridfrom);
 701          $this->assertEquals(fullname($user2), $message1->fullname);
 702          $this->assertTrue($message1->ismessaging);
 703          $this->assertEquals('Word.', $message1->lastmessage);
 704          $this->assertNotEmpty($message1->messageid);
 705          $this->assertNull($message1->isonline);
 706          $this->assertFalse($message1->isread);
 707          $this->assertFalse($message1->isblocked);
 708          $this->assertNull($message1->unreadcount);
 709          $this->assertEquals($convid, $message1->conversationid);
 710  
 711          $this->assertEquals($user2->id, $message2->userid);
 712          $this->assertEquals($user1->id, $message2->useridfrom);
 713          $this->assertEquals(fullname($user2), $message2->fullname);
 714          $this->assertTrue($message2->ismessaging);
 715          $this->assertEquals('Yo!', $message2->lastmessage);
 716          $this->assertNotEmpty($message2->messageid);
 717          $this->assertNull($message2->isonline);
 718          $this->assertTrue($message2->isread);
 719          $this->assertFalse($message2->isblocked);
 720          $this->assertNull($message2->unreadcount);
 721          $this->assertEquals($convid, $message2->conversationid);
 722  
 723          $this->assertEquals($user3->id, $message3->userid);
 724          $this->assertEquals($user3->id, $message3->useridfrom);
 725          $this->assertEquals(fullname($user3), $message3->fullname);
 726          $this->assertTrue($message3->ismessaging);
 727          $this->assertEquals('Don\'t block me.', $message3->lastmessage);
 728          $this->assertNotEmpty($message3->messageid);
 729          $this->assertNull($message3->isonline);
 730          $this->assertFalse($message3->isread);
 731          $this->assertTrue($message3->isblocked);
 732          $this->assertNull($message3->unreadcount);
 733          $this->assertEquals($conv2id, $message3->conversationid);
 734  
 735          // This is a group conversation. For now, search_messages returns only one of the other users on the conversation. It can't
 736          // be guaranteed who will be returned in the first place, so we need to use the in_array to check all the possibilities.
 737          $this->assertTrue(in_array($message4->userid, [$user2->id, $user3->id]));
 738          $this->assertEquals($user1->id, $message4->useridfrom);
 739          $this->assertTrue($message4->ismessaging);
 740          $this->assertEquals('My hero!', $message4->lastmessage);
 741          $this->assertNotEmpty($message4->messageid);
 742          $this->assertNull($message4->isonline);
 743          $this->assertTrue($message4->isread);
 744          $this->assertNull($message4->unreadcount);
 745          $this->assertEquals($gc->id, $message4->conversationid);
 746  
 747          $this->assertEquals($user1->id, $message5->userid);
 748          $this->assertEquals($user1->id, $message5->useridfrom);
 749          $this->assertEquals(fullname($user1), $message5->fullname);
 750          $this->assertTrue($message5->ismessaging);
 751          $this->assertEquals('Test message to self!', $message5->lastmessage);
 752          $this->assertNotEmpty($message5->messageid);
 753          $this->assertFalse($message5->isonline);
 754          $this->assertTrue($message5->isread);
 755          $this->assertFalse($message5->isblocked);
 756          $this->assertNull($message5->unreadcount);
 757          $this->assertEquals($sc->id, $message5->conversationid);
 758      }
 759  
 760      /**
 761       * Test verifying that favourited conversations can be retrieved.
 762       */
 763      public function test_get_favourite_conversations() {
 764          // Create some users.
 765          $user1 = self::getDataGenerator()->create_user();
 766          $user2 = self::getDataGenerator()->create_user();
 767          $user3 = self::getDataGenerator()->create_user();
 768          $user4 = self::getDataGenerator()->create_user();
 769  
 770          // The person doing the search.
 771          $this->setUser($user1);
 772  
 773          // Only self-conversation created.
 774          $this->assertCount(1, api::get_conversations($user1->id));
 775  
 776          // Create some conversations for user1.
 777          $time = 1;
 778          $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
 779          $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
 780          $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
 781          $messageid1 = $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
 782  
 783          $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
 784          $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
 785          $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
 786          $messageid2 = $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
 787  
 788          $this->send_fake_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?', 0, $time + 9);
 789          $this->send_fake_message($user4, $user1, 'Yah brah, it\'s pretty rad.', 0, $time + 10);
 790          $messageid3 = $this->send_fake_message($user1, $user4, 'Dope.', 0, $time + 11);
 791  
 792          // Favourite the first 2 conversations for user1.
 793          $convoids = [];
 794          $convoids[] = api::get_conversation_between_users([$user1->id, $user2->id]);
 795          $convoids[] = api::get_conversation_between_users([$user1->id, $user3->id]);
 796          $user1context = \context_user::instance($user1->id);
 797          $service = \core_favourites\service_factory::get_service_for_user_context($user1context);
 798          foreach ($convoids as $convoid) {
 799              $service->create_favourite('core_message', 'message_conversations', $convoid, $user1context);
 800          }
 801  
 802          // We should have 4 conversations.
 803          // Consider first conversations is self-conversation.
 804          $this->assertCount(4, api::get_conversations($user1->id));
 805  
 806          // And 3 favourited conversations (self-conversation included).
 807          $conversations = api::get_conversations($user1->id, 0, 20, null, true);
 808          $this->assertCount(3, $conversations);
 809          $conversations = api::get_conversations(
 810              $user1->id,
 811              0,
 812              20,
 813              api::MESSAGE_CONVERSATION_TYPE_SELF,
 814              true
 815          );
 816          $this->assertCount(1, $conversations);
 817      }
 818  
 819      /**
 820       * Tests retrieving favourite conversations with a limit and offset to ensure pagination works correctly.
 821       */
 822      public function test_get_favourite_conversations_limit_offset() {
 823          // Create some users.
 824          $user1 = self::getDataGenerator()->create_user();
 825          $user2 = self::getDataGenerator()->create_user();
 826          $user3 = self::getDataGenerator()->create_user();
 827          $user4 = self::getDataGenerator()->create_user();
 828  
 829          // The person doing the search.
 830          $this->setUser($user1);
 831  
 832          // Only self-conversation created.
 833          $this->assertCount(1, api::get_conversations($user1->id));
 834  
 835          // Create some conversations for user1.
 836          $time = 1;
 837          $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
 838          $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
 839          $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
 840          $messageid1 = $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
 841  
 842          $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
 843          $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
 844          $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
 845          $messageid2 = $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
 846  
 847          $this->send_fake_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?', 0, $time + 9);
 848          $this->send_fake_message($user4, $user1, 'Yah brah, it\'s pretty rad.', 0, $time + 10);
 849          $messageid3 = $this->send_fake_message($user1, $user4, 'Dope.', 0, $time + 11);
 850  
 851          // Favourite the all conversations for user1.
 852          $convoids = [];
 853          $convoids[] = api::get_conversation_between_users([$user1->id, $user2->id]);
 854          $convoids[] = api::get_conversation_between_users([$user1->id, $user3->id]);
 855          $convoids[] = api::get_conversation_between_users([$user1->id, $user4->id]);
 856          $user1context = \context_user::instance($user1->id);
 857          $service = \core_favourites\service_factory::get_service_for_user_context($user1context);
 858          foreach ($convoids as $convoid) {
 859              $service->create_favourite('core_message', 'message_conversations', $convoid, $user1context);
 860          }
 861  
 862          // Consider first conversations is self-conversation.
 863          // Get all records, using offset 0 and large limit.
 864          $this->assertCount(4, api::get_conversations($user1->id, 0, 20, null, true));
 865  
 866          // Now, get 10 conversations starting at the second record. We should see 2 conversations.
 867          $this->assertCount(3, api::get_conversations($user1->id, 1, 10, null, true));
 868  
 869          // Now, try to get favourited conversations using an invalid offset.
 870          $this->assertCount(0, api::get_conversations($user1->id, 5, 10, null, true));
 871      }
 872  
 873      /**
 874       * Tests retrieving favourite conversations when a conversation contains a deleted user.
 875       */
 876      public function test_get_favourite_conversations_with_deleted_user() {
 877          // Create some users.
 878          $user1 = self::getDataGenerator()->create_user();
 879          $user2 = self::getDataGenerator()->create_user();
 880          $user3 = self::getDataGenerator()->create_user();
 881  
 882          // Send some messages back and forth, have some different conversations with different users.
 883          $time = 1;
 884          $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
 885          $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
 886          $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
 887          $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
 888  
 889          $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
 890          $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
 891          $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
 892          $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
 893  
 894          // Favourite the all conversations for user1.
 895          $convoids = [];
 896          $convoids[] = api::get_conversation_between_users([$user1->id, $user2->id]);
 897          $convoids[] = api::get_conversation_between_users([$user1->id, $user3->id]);
 898          $user1context = \context_user::instance($user1->id);
 899          $service = \core_favourites\service_factory::get_service_for_user_context($user1context);
 900          foreach ($convoids as $convoid) {
 901              $service->create_favourite('core_message', 'message_conversations', $convoid, $user1context);
 902          }
 903  
 904          // Delete the second user.
 905          delete_user($user2);
 906  
 907          // Retrieve the conversations.
 908          $conversations = api::get_conversations($user1->id, 0, 20, null, true);
 909  
 910          // We should have both conversations, despite the other user being soft-deleted.
 911          // Consider first conversations is self-conversation.
 912          $this->assertCount(3, $conversations);
 913  
 914          // Confirm the conversation is from the non-deleted user.
 915          $conversation = reset($conversations);
 916          $this->assertEquals($convoids[1], $conversation->id);
 917      }
 918  
 919      /**
 920       * Test confirming that conversations can be marked as favourites.
 921       */
 922      public function test_set_favourite_conversation() {
 923          // Create some users.
 924          $user1 = self::getDataGenerator()->create_user();
 925          $user2 = self::getDataGenerator()->create_user();
 926          $user3 = self::getDataGenerator()->create_user();
 927  
 928          // Send some messages back and forth, have some different conversations with different users.
 929          $time = 1;
 930          $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
 931          $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
 932          $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
 933          $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
 934  
 935          $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
 936          $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
 937          $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
 938          $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
 939  
 940          // Favourite the first conversation as user 1.
 941          $conversationid1 = api::get_conversation_between_users([$user1->id, $user2->id]);
 942          $favourite = api::set_favourite_conversation($conversationid1, $user1->id);
 943  
 944          // Verify we have two favourite conversations a user 1.
 945          // Consider first conversations is self-conversation.
 946          $this->assertCount(2, api::get_conversations($user1->id, 0, 20, null, true));
 947  
 948          // Verify we have only one favourite as user2, despite being a member in that conversation.
 949          // Consider first conversations is self-conversation.
 950          $this->assertCount(1, api::get_conversations($user2->id, 0, 20, null, true));
 951  
 952          // Try to favourite the same conversation again should just return the existing favourite.
 953          $repeatresult = api::set_favourite_conversation($conversationid1, $user1->id);
 954          $this->assertEquals($favourite->id, $repeatresult->id);
 955      }
 956  
 957      /**
 958       * Test verifying that trying to mark a non-existent conversation as a favourite, results in an exception.
 959       */
 960      public function test_set_favourite_conversation_nonexistent_conversation() {
 961          // Create some users.
 962          $user1 = self::getDataGenerator()->create_user();
 963          // Try to favourite a non-existent conversation.
 964          $this->expectException(\moodle_exception::class);
 965          api::set_favourite_conversation(0, $user1->id);
 966      }
 967  
 968      /**
 969       * Test verifying that a conversation cannot be marked as favourite unless the user is a member of that conversation.
 970       */
 971      public function test_set_favourite_conversation_non_member() {
 972          // Create some users.
 973          $user1 = self::getDataGenerator()->create_user();
 974          $user2 = self::getDataGenerator()->create_user();
 975          $user3 = self::getDataGenerator()->create_user();
 976  
 977          // Send some messages back and forth, have some different conversations with different users.
 978          $time = 1;
 979          $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
 980          $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
 981          $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
 982          $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
 983  
 984          $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
 985          $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
 986          $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
 987          $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
 988  
 989          // Try to favourite the first conversation as user 3, who is not a member.
 990          $conversationid1 = api::get_conversation_between_users([$user1->id, $user2->id]);
 991          $this->expectException(\moodle_exception::class);
 992          api::set_favourite_conversation($conversationid1, $user3->id);
 993      }
 994  
 995      /**
 996       * Test confirming that those conversations marked as favourites can be unfavourited.
 997       */
 998      public function test_unset_favourite_conversation() {
 999          // Create some users.
1000          $user1 = self::getDataGenerator()->create_user();
1001          $user2 = self::getDataGenerator()->create_user();
1002          $user3 = self::getDataGenerator()->create_user();
1003  
1004          // Send some messages back and forth, have some different conversations with different users.
1005          $time = 1;
1006          $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
1007          $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
1008          $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
1009          $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
1010  
1011          $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5);
1012          $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6);
1013          $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7);
1014          $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8);
1015  
1016          // Favourite the first conversation as user 1 and the second as user 3.
1017          $conversationid1 = api::get_conversation_between_users([$user1->id, $user2->id]);
1018          $conversationid2 = api::get_conversation_between_users([$user1->id, $user3->id]);
1019          api::set_favourite_conversation($conversationid1, $user1->id);
1020          api::set_favourite_conversation($conversationid2, $user3->id);
1021  
1022          // Verify we have two favourite conversations for both user 1 and user 3, counting self conversations.
1023          $this->assertCount(2, api::get_conversations($user1->id, 0, 20, null, true));
1024          $this->assertCount(2, api::get_conversations($user3->id, 0, 20, null, true));
1025  
1026          // Now unfavourite the conversation as user 1.
1027          api::unset_favourite_conversation($conversationid1, $user1->id);
1028  
1029          // Verify we have two favourite conversations user 3 only, and one for user1, counting self conversations.
1030          $this->assertCount(2, api::get_conversations($user3->id, 0, 20, null, true));
1031          $this->assertCount(1, api::get_conversations($user1->id, 0, 20, null, true));
1032  
1033          // Try to favourite the same conversation again as user 1.
1034          $this->expectException(\moodle_exception::class);
1035          api::unset_favourite_conversation($conversationid1, $user1->id);
1036      }
1037  
1038      /**
1039       * Test verifying that a valid conversation cannot be unset as a favourite if it's not marked as a favourite.
1040       */
1041      public function test_unset_favourite_conversation_not_favourite() {
1042          // Create some users.
1043          $user1 = self::getDataGenerator()->create_user();
1044          $user2 = self::getDataGenerator()->create_user();
1045  
1046          // Send some messages back and forth, have some different conversations with different users.
1047          $time = 1;
1048          $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
1049          $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
1050          $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
1051          $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
1052  
1053          // Now try to unfavourite the conversation as user 1.
1054          $conversationid1 = api::get_conversation_between_users([$user1->id, $user2->id]);
1055          $this->expectException(\moodle_exception::class);
1056          api::unset_favourite_conversation($conversationid1, $user1->id);
1057      }
1058  
1059      /**
1060       * Test verifying that a non-existent conversation cannot be unset as a favourite.
1061       */
1062      public function test_unset_favourite_conversation_non_existent_conversation() {
1063          // Create some users.
1064          $user1 = self::getDataGenerator()->create_user();
1065  
1066          // Now try to unfavourite the conversation as user 1.
1067          $this->expectException(\moodle_exception::class);
1068          api::unset_favourite_conversation(0, $user1->id);
1069      }
1070  
1071      /**
1072       * Helper to seed the database with initial state.
1073       */
1074      protected function create_conversation_test_data() {
1075          // Create some users.
1076          $user1 = self::getDataGenerator()->create_user();
1077          $user2 = self::getDataGenerator()->create_user();
1078          $user3 = self::getDataGenerator()->create_user();
1079          $user4 = self::getDataGenerator()->create_user();
1080  
1081          $time = 1;
1082  
1083          // Create some conversations. We want:
1084          // 1) At least one of each type (group, individual) of which user1 IS a member and DID send the most recent message.
1085          // 2) At least one of each type (group, individual) of which user1 IS a member and DID NOT send the most recent message.
1086          // 3) At least one of each type (group, individual) of which user1 IS NOT a member.
1087          // 4) At least two group conversation having 0 messages, of which user1 IS a member (To confirm conversationid ordering).
1088          // 5) At least one group conversation having 0 messages, of which user1 IS NOT a member.
1089  
1090          // Individual conversation, user1 is a member, last message from other user.
1091          $ic1 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1092              [$user1->id, $user2->id]);
1093          testhelper::send_fake_message_to_conversation($user1, $ic1->id, 'Message 1', $time);
1094          testhelper::send_fake_message_to_conversation($user2, $ic1->id, 'Message 2', $time + 1);
1095  
1096          // Individual conversation, user1 is a member, last message from user1.
1097          $ic2 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1098              [$user1->id, $user3->id]);
1099          testhelper::send_fake_message_to_conversation($user3, $ic2->id, 'Message 3', $time + 2);
1100          testhelper::send_fake_message_to_conversation($user1, $ic2->id, 'Message 4', $time + 3);
1101  
1102          // Individual conversation, user1 is not a member.
1103          $ic3 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1104              [$user2->id, $user3->id]);
1105          testhelper::send_fake_message_to_conversation($user2, $ic3->id, 'Message 5', $time + 4);
1106          testhelper::send_fake_message_to_conversation($user3, $ic3->id, 'Message 6', $time + 5);
1107  
1108          // Group conversation, user1 is not a member.
1109          $gc1 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_GROUP,
1110              [$user2->id, $user3->id, $user4->id], 'Project discussions');
1111          testhelper::send_fake_message_to_conversation($user2, $gc1->id, 'Message 7', $time + 6);
1112          testhelper::send_fake_message_to_conversation($user4, $gc1->id, 'Message 8', $time + 7);
1113  
1114          // Group conversation, user1 is a member, last message from another user.
1115          $gc2 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_GROUP,
1116              [$user1->id, $user3->id, $user4->id], 'Group chat');
1117          testhelper::send_fake_message_to_conversation($user1, $gc2->id, 'Message 9', $time + 8);
1118          testhelper::send_fake_message_to_conversation($user3, $gc2->id, 'Message 10', $time + 9);
1119          testhelper::send_fake_message_to_conversation($user4, $gc2->id, 'Message 11', $time + 10);
1120  
1121          // Group conversation, user1 is a member, last message from user1.
1122          $gc3 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_GROUP,
1123              [$user1->id, $user2->id, $user3->id, $user4->id], 'Group chat again!');
1124          testhelper::send_fake_message_to_conversation($user4, $gc3->id, 'Message 12', $time + 11);
1125          testhelper::send_fake_message_to_conversation($user3, $gc3->id, 'Message 13', $time + 12);
1126          testhelper::send_fake_message_to_conversation($user1, $gc3->id, 'Message 14', $time + 13);
1127  
1128          // Empty group conversations (x2), user1 is a member.
1129          $gc4 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_GROUP,
1130              [$user1->id, $user2->id, $user3->id], 'Empty group');
1131          $gc5 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_GROUP,
1132              [$user1->id, $user2->id, $user4->id], 'Another empty group');
1133  
1134          // Empty group conversation, user1 is NOT a member.
1135          $gc6 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_GROUP,
1136              [$user2->id, $user3->id, $user4->id], 'Empty group 3');
1137  
1138          return [$user1, $user2, $user3, $user4, $ic1, $ic2, $ic3, $gc1, $gc2, $gc3, $gc4, $gc5, $gc6];
1139      }
1140  
1141      /**
1142       * Test verifying get_conversations when no limits, offsets, type filters or favourite restrictions are used.
1143       */
1144      public function test_get_conversations_no_restrictions() {
1145          global $DB;
1146  
1147          $user1 = self::getDataGenerator()->create_user();
1148          // Self-conversation should exists.
1149          $this->assertCount(1, api::get_conversations($user1->id));
1150  
1151          // Get a bunch of conversations, some group, some individual and in different states.
1152          list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1153              $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1154  
1155          // Get all conversations for user1.
1156          $conversations = api::get_conversations($user1->id);
1157  
1158          // Verify there are 2 individual conversation, 2 group conversations, 2 empty group conversations,
1159          // and a self-conversation.
1160          // The conversations with the most recent messages should be listed first, followed by the empty
1161          // conversations, with the most recently created first.
1162          $this->assertCount(7, $conversations);
1163          $typecounts  = array_count_values(array_column($conversations, 'type'));
1164          $this->assertEquals(2, $typecounts[1]);
1165          $this->assertEquals(4, $typecounts[2]);
1166          $this->assertEquals(1, $typecounts[3]);
1167  
1168          // Those conversations having messages should be listed after self-conversation, ordered by most recent message time.
1169          $this->assertEquals($gc3->id, $conversations[0]->id);
1170          $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_GROUP, $conversations[0]->type);
1171          $this->assertFalse($conversations[1]->isfavourite);
1172          $this->assertCount(1, $conversations[0]->members);
1173          $this->assertEquals(4, $conversations[0]->membercount);
1174          $this->assertCount(1, $conversations[0]->messages);
1175          $message = $DB->get_record('messages', ['id' => $conversations[0]->messages[0]->id]);
1176          $expectedmessagetext = message_format_message_text($message);
1177          $this->assertEquals($expectedmessagetext, $conversations[0]->messages[0]->text);
1178          $this->assertEquals($user1->id, $conversations[0]->messages[0]->useridfrom);
1179  
1180          $this->assertEquals($gc2->id, $conversations[1]->id);
1181          $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_GROUP, $conversations[1]->type);
1182          $this->assertFalse($conversations[1]->isfavourite);
1183          $this->assertCount(1, $conversations[1]->members);
1184          $this->assertEquals(3, $conversations[1]->membercount);
1185          $this->assertCount(1, $conversations[1]->messages);
1186          $message = $DB->get_record('messages', ['id' => $conversations[1]->messages[0]->id]);
1187          $expectedmessagetext = message_format_message_text($message);
1188          $this->assertEquals($expectedmessagetext, $conversations[1]->messages[0]->text);
1189          $this->assertEquals($user4->id, $conversations[1]->messages[0]->useridfrom);
1190  
1191          $this->assertEquals($ic2->id, $conversations[2]->id);
1192          $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $conversations[2]->type);
1193          $this->assertFalse($conversations[2]->isfavourite);
1194          $this->assertCount(1, $conversations[2]->members);
1195          $this->assertEquals($user3->id, $conversations[2]->members[$user3->id]->id);
1196          $this->assertEquals(2, $conversations[2]->membercount);
1197          $this->assertCount(1, $conversations[2]->messages);
1198          $message = $DB->get_record('messages', ['id' => $conversations[2]->messages[0]->id]);
1199          $expectedmessagetext = message_format_message_text($message);
1200          $this->assertEquals($expectedmessagetext, $conversations[2]->messages[0]->text);
1201          $this->assertEquals($user1->id, $conversations[2]->messages[0]->useridfrom);
1202  
1203          $this->assertEquals($ic1->id, $conversations[3]->id);
1204          $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $conversations[3]->type);
1205          $this->assertFalse($conversations[3]->isfavourite);
1206          $this->assertCount(1, $conversations[3]->members);
1207          $this->assertEquals(2, $conversations[3]->membercount);
1208          $this->assertCount(1, $conversations[3]->messages);
1209          $message = $DB->get_record('messages', ['id' => $conversations[3]->messages[0]->id]);
1210          $expectedmessagetext = message_format_message_text($message);
1211          $this->assertEquals($expectedmessagetext, $conversations[3]->messages[0]->text);
1212          $this->assertEquals($user2->id, $conversations[3]->messages[0]->useridfrom);
1213  
1214          // Of the groups without messages, we expect to see the most recently created first.
1215          $this->assertEquals($gc5->id, $conversations[4]->id);
1216          $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_GROUP, $conversations[4]->type);
1217          $this->assertFalse($conversations[4]->isfavourite);
1218          $this->assertCount(0, $conversations[4]->members); // No members returned, because no recent messages exist.
1219          $this->assertEquals(3, $conversations[4]->membercount);
1220          $this->assertEmpty($conversations[4]->messages);
1221  
1222          $this->assertEquals($gc4->id, $conversations[5]->id);
1223          $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_GROUP, $conversations[5]->type);
1224          $this->assertFalse($conversations[5]->isfavourite);
1225          $this->assertCount(0, $conversations[5]->members);
1226          $this->assertEquals(3, $conversations[5]->membercount);
1227          $this->assertEmpty($conversations[5]->messages);
1228  
1229          // Verify format of the return structure.
1230          foreach ($conversations as $conv) {
1231              $this->assertObjectHasAttribute('id', $conv);
1232              $this->assertObjectHasAttribute('name', $conv);
1233              $this->assertObjectHasAttribute('subname', $conv);
1234              $this->assertObjectHasAttribute('imageurl', $conv);
1235              $this->assertObjectHasAttribute('type', $conv);
1236              $this->assertObjectHasAttribute('isfavourite', $conv);
1237              $this->assertObjectHasAttribute('membercount', $conv);
1238              $this->assertObjectHasAttribute('isread', $conv);
1239              $this->assertObjectHasAttribute('unreadcount', $conv);
1240              $this->assertObjectHasAttribute('members', $conv);
1241              foreach ($conv->members as $member) {
1242                  $this->assertObjectHasAttribute('id', $member);
1243                  $this->assertObjectHasAttribute('fullname', $member);
1244                  $this->assertObjectHasAttribute('profileimageurl', $member);
1245                  $this->assertObjectHasAttribute('profileimageurlsmall', $member);
1246                  $this->assertObjectHasAttribute('isonline', $member);
1247                  $this->assertObjectHasAttribute('showonlinestatus', $member);
1248                  $this->assertObjectHasAttribute('isblocked', $member);
1249                  $this->assertObjectHasAttribute('iscontact', $member);
1250                  $this->assertObjectHasAttribute('isdeleted', $member);
1251                  $this->assertObjectHasAttribute('canmessage', $member);
1252                  $this->assertObjectHasAttribute('requirescontact', $member);
1253                  $this->assertObjectHasAttribute('contactrequests', $member);
1254              }
1255              $this->assertObjectHasAttribute('messages', $conv);
1256              foreach ($conv->messages as $message) {
1257                  $this->assertObjectHasAttribute('id', $message);
1258                  $this->assertObjectHasAttribute('useridfrom', $message);
1259                  $this->assertObjectHasAttribute('text', $message);
1260                  $this->assertObjectHasAttribute('timecreated', $message);
1261              }
1262          }
1263      }
1264  
1265      /**
1266       * Test verifying that html format messages are supported, and that message_format_message_text() is being called appropriately.
1267       */
1268      public function test_get_conversations_message_format() {
1269          global $DB;
1270          // Create some users.
1271          $user1 = self::getDataGenerator()->create_user();
1272          $user2 = self::getDataGenerator()->create_user();
1273  
1274          // Create conversation.
1275          $conversation = api::create_conversation(
1276              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1277              [$user1->id, $user2->id]
1278          );
1279  
1280          // Send some messages back and forth.
1281          $time = 1;
1282          testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 1);
1283          $mid = testhelper::send_fake_message_to_conversation($user1, $conversation->id, '<a href="#">A link</a>', $time + 2);
1284  
1285          // Verify the format of the html message.
1286          $message = $DB->get_record('messages', ['id' => $mid]);
1287          $expectedmessagetext = message_format_message_text($message);
1288          $conversations = api::get_conversations($user1->id);
1289          $messages = $conversations[0]->messages;
1290          $this->assertEquals($expectedmessagetext, $messages[0]->text);
1291      }
1292  
1293      /**
1294       * Test verifying get_conversations identifies if a conversation is muted or not.
1295       */
1296      public function test_get_conversations_some_muted() {
1297          // Create some users.
1298          $user1 = self::getDataGenerator()->create_user();
1299          $user2 = self::getDataGenerator()->create_user();
1300          $user3 = self::getDataGenerator()->create_user();
1301  
1302          $conversation1 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1303              [$user1->id, $user2->id]);
1304          testhelper::send_fake_message_to_conversation($user1, $conversation1->id, 'Message 1');
1305          testhelper::send_fake_message_to_conversation($user2, $conversation1->id, 'Message 2');
1306          api::mute_conversation($user1->id, $conversation1->id);
1307  
1308          $conversation2 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1309              [$user1->id, $user3->id]);
1310          testhelper::send_fake_message_to_conversation($user1, $conversation2->id, 'Message 1');
1311          testhelper::send_fake_message_to_conversation($user2, $conversation2->id, 'Message 2');
1312  
1313          $conversation3 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_GROUP,
1314              [$user1->id, $user2->id]);
1315          api::mute_conversation($user1->id, $conversation3->id);
1316  
1317          $conversation4 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_GROUP,
1318              [$user1->id, $user3->id]);
1319  
1320          $conversations = api::get_conversations($user1->id);
1321  
1322          usort($conversations, function($first, $second){
1323              return $first->id <=> $second->id;
1324          });
1325  
1326          // Consider first conversations is self-conversation.
1327          $selfconversation = array_shift($conversations);
1328          $conv1 = array_shift($conversations);
1329          $conv2 = array_shift($conversations);
1330          $conv3 = array_shift($conversations);
1331          $conv4 = array_shift($conversations);
1332  
1333          $this->assertTrue($conv1->ismuted);
1334          $this->assertFalse($conv2->ismuted);
1335          $this->assertTrue($conv3->ismuted);
1336          $this->assertFalse($conv4->ismuted);
1337      }
1338  
1339      /**
1340       * Tests retrieving conversations with a limit and offset to ensure pagination works correctly.
1341       */
1342      public function test_get_conversations_limit_offset() {
1343          // Get a bunch of conversations, some group, some individual and in different states.
1344          list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1345              $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1346  
1347          // Get all conversations for user1, limited to 1 result.
1348          $conversations = api::get_conversations($user1->id, 0, 1);
1349  
1350          // Verify the first conversation.
1351          $this->assertCount(1, $conversations);
1352          $conversation = array_shift($conversations);
1353          $this->assertEquals($conversation->id, $gc3->id);
1354  
1355          // Verify the next conversation.
1356          $conversations = api::get_conversations($user1->id, 1, 1);
1357          $this->assertCount(1, $conversations);
1358          $this->assertEquals($gc2->id, $conversations[0]->id);
1359  
1360          // Verify the next conversation.
1361          $conversations = api::get_conversations($user1->id, 2, 1);
1362          $this->assertCount(1, $conversations);
1363          $this->assertEquals($ic2->id, $conversations[0]->id);
1364  
1365          // Skip one and get both empty conversations.
1366          $conversations = api::get_conversations($user1->id, 4, 2);
1367          $this->assertCount(2, $conversations);
1368          $this->assertEquals($gc5->id, $conversations[0]->id);
1369          $this->assertEmpty($conversations[0]->messages);
1370          $this->assertEquals($gc4->id, $conversations[1]->id);
1371          $this->assertEmpty($conversations[1]->messages);
1372  
1373          // Ask for an offset that doesn't exist and verify no conversations are returned.
1374          $conversations = api::get_conversations($user1->id, 10, 1);
1375          $this->assertCount(0, $conversations);
1376      }
1377  
1378      /**
1379       * Test verifying the type filtering behaviour of the
1380       */
1381      public function test_get_conversations_type_filter() {
1382          // Get a bunch of conversations, some group, some individual and in different states.
1383          list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1384              $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1385  
1386          // Verify we can ask for only individual conversations.
1387          $conversations = api::get_conversations($user1->id, 0, 20,
1388              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL);
1389          $this->assertCount(2, $conversations);
1390  
1391          // Verify we can ask for only group conversations.
1392          $conversations = api::get_conversations($user1->id, 0, 20,
1393              api::MESSAGE_CONVERSATION_TYPE_GROUP);
1394          $this->assertCount(4, $conversations);
1395  
1396          // Verify an exception is thrown if an unrecognized type is specified.
1397          $this->expectException(\moodle_exception::class);
1398          $conversations = api::get_conversations($user1->id, 0, 20, 0);
1399      }
1400  
1401      /**
1402       * Tests retrieving conversations when a 'self' conversation exists.
1403       */
1404      public function test_get_conversations_self_conversations() {
1405          global $DB;
1406  
1407          // Create a conversation between one user and themself.
1408          $user1 = self::getDataGenerator()->create_user();
1409          $user2 = self::getDataGenerator()->create_user();
1410          $user3 = self::getDataGenerator()->create_user();
1411          $user4 = self::getDataGenerator()->create_user();
1412  
1413          // Create some individual conversations.
1414          $ic1 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1415              [$user1->id, $user2->id]);
1416          $ic2 = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1417              [$user1->id, $user3->id]);
1418          testhelper::send_fake_message_to_conversation($user1, $ic1->id, 'Message from user1 to user2');
1419  
1420          // Get some self-conversations.
1421          $sc1 = api::get_self_conversation($user1->id);
1422          $sc4 = api::get_self_conversation($user4->id);
1423          testhelper::send_fake_message_to_conversation($user1, $sc1->id, 'Test message to self 1!');
1424  
1425          // Verify we are in a 'self' conversation state.
1426          $members = $DB->get_records('message_conversation_members', ['conversationid' => $sc1->id]);
1427          $this->assertCount(1, $members);
1428          $member = array_pop($members);
1429          $this->assertEquals($user1->id, $member->userid);
1430  
1431          // Verify the self-conversations are returned by the method.
1432          $conversations = api::get_conversations($user1->id, 0, 20, api::MESSAGE_CONVERSATION_TYPE_SELF);
1433          $this->assertCount(1, $conversations);
1434          $conversation = array_pop($conversations);
1435          $this->assertEquals($conversation->id, $sc1->id);
1436  
1437          $conversations = api::get_conversations($user4->id);
1438          // The self-conversation.
1439          $this->assertCount(1, $conversations);
1440  
1441          // Get only private conversations for user1 (empty conversations, like $ic2, are not returned).
1442          $conversations = api::get_conversations($user1->id, 0, 20,
1443              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL);
1444          $this->assertCount(1, $conversations);
1445  
1446          // Merge self with private conversations for user1.
1447          $conversations = api::get_conversations($user1->id, 0, 20,
1448              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, null, true);
1449          $this->assertCount(2, $conversations);
1450  
1451          // Get only private conversations for user2.
1452          $conversations = api::get_conversations($user2->id, 0, 20,
1453              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL);
1454          $this->assertCount(1, $conversations);
1455  
1456          // Merge self with private conversations for user2.
1457          $conversations = api::get_conversations($user2->id, 0, 20,
1458              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, null, true);
1459          $this->assertCount(2, $conversations);
1460      }
1461  
1462      /**
1463       * Tests retrieving conversations when a conversation contains a deleted user.
1464       */
1465      public function test_get_conversations_with_deleted_user() {
1466          // Get a bunch of conversations, some group, some individual and in different states.
1467          list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1468              $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1469  
1470          // Delete the second user and retrieve the conversations.
1471          // We should have 6 still, as conversations with soft-deleted users are still returned.
1472          // Group conversations are also present, albeit with less members.
1473          delete_user($user2);
1474          // This is to confirm an exception is not thrown when a user AND the user context is deleted.
1475          // We no longer delete the user context, but historically we did.
1476          \context_helper::delete_instance(CONTEXT_USER, $user2->id);
1477          $conversations = api::get_conversations($user1->id);
1478          // Consider there's a self-conversation (the last one).
1479          $this->assertCount(7, $conversations);
1480          $this->assertEquals($gc3->id, $conversations[0]->id);
1481          $this->assertcount(1, $conversations[0]->members);
1482          $this->assertEquals($gc2->id, $conversations[1]->id);
1483          $this->assertcount(1, $conversations[1]->members);
1484          $this->assertEquals($ic2->id, $conversations[2]->id);
1485          $this->assertEquals($ic1->id, $conversations[3]->id);
1486          $this->assertEquals($gc5->id, $conversations[4]->id);
1487          $this->assertEquals($gc4->id, $conversations[5]->id);
1488  
1489          // Delete a user from a group conversation where that user had sent the most recent message.
1490          // This user will still be present in the members array, as will the message in the messages array.
1491          delete_user($user4);
1492          $conversations = api::get_conversations($user1->id);
1493  
1494          // Consider there's a self-conversation (the last one).
1495          $this->assertCount(7, $conversations);
1496          $this->assertEquals($gc2->id, $conversations[1]->id);
1497          $this->assertcount(1, $conversations[1]->members);
1498          $this->assertEquals($user4->id, $conversations[1]->members[$user4->id]->id);
1499          $this->assertcount(1, $conversations[1]->messages);
1500          $this->assertEquals($user4->id, $conversations[1]->messages[0]->useridfrom);
1501  
1502          // Delete the third user and retrieve the conversations.
1503          // We should have 6 still, as conversations with soft-deleted users are still returned.
1504          // Group conversations are also present, albeit with less members.
1505          delete_user($user3);
1506          $conversations = api::get_conversations($user1->id);
1507          // Consider there's a self-conversation (the last one).
1508          $this->assertCount(7, $conversations);
1509          $this->assertEquals($gc3->id, $conversations[0]->id);
1510          $this->assertcount(1, $conversations[0]->members);
1511          $this->assertEquals($gc2->id, $conversations[1]->id);
1512          $this->assertcount(1, $conversations[1]->members);
1513          $this->assertEquals($ic2->id, $conversations[2]->id);
1514          $this->assertEquals($ic1->id, $conversations[3]->id);
1515          $this->assertEquals($gc5->id, $conversations[4]->id);
1516          $this->assertEquals($gc4->id, $conversations[5]->id);
1517      }
1518  
1519      /**
1520       * Test confirming the behaviour of get_conversations() when users delete all messages.
1521       */
1522      public function test_get_conversations_deleted_messages() {
1523          // Get a bunch of conversations, some group, some individual and in different states.
1524          list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1525              $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1526  
1527          $conversations = api::get_conversations($user1->id);
1528          // Consider first conversations is self-conversation.
1529          $this->assertCount(7, $conversations);
1530  
1531          // Delete all messages from a group conversation the user is in - it should be returned.
1532          $this->assertTrue(api::is_user_in_conversation($user1->id, $gc2->id));
1533          $convmessages = api::get_conversation_messages($user1->id, $gc2->id);
1534          $messages = $convmessages['messages'];
1535          foreach ($messages as $message) {
1536              api::delete_message($user1->id, $message->id);
1537          }
1538          $conversations = api::get_conversations($user1->id);
1539          // Consider first conversations is self-conversation.
1540          $this->assertCount(7, $conversations);
1541          $this->assertContainsEquals($gc2->id, array_column($conversations, 'id'));
1542  
1543          // Delete all messages from an individual conversation the user is in - it should not be returned.
1544          $this->assertTrue(api::is_user_in_conversation($user1->id, $ic1->id));
1545          $convmessages = api::get_conversation_messages($user1->id, $ic1->id);
1546          $messages = $convmessages['messages'];
1547          foreach ($messages as $message) {
1548              api::delete_message($user1->id, $message->id);
1549          }
1550          $conversations = api::get_conversations($user1->id);
1551          // Consider first conversations is self-conversation.
1552          $this->assertCount(6, $conversations);
1553          $this->assertNotContainsEquals($ic1->id, array_column($conversations, 'id'));
1554      }
1555  
1556      /**
1557       * Test verifying the behaviour of get_conversations() when fetching favourite conversations with only a single
1558       * favourite.
1559       */
1560      public function test_get_conversations_favourite_conversations_single() {
1561          // Get a bunch of conversations, some group, some individual and in different states.
1562          list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1563              $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1564  
1565          // Mark a single conversation as favourites.
1566          api::set_favourite_conversation($ic2->id, $user1->id);
1567  
1568          // Get the conversation, first with no restrictions, confirming the favourite status of the conversations.
1569          $conversations = api::get_conversations($user1->id);
1570          // Consider there is a self-conversation.
1571          $selfconversation = api::get_self_conversation($user1->id);
1572          $this->assertCount(7, $conversations);
1573          foreach ($conversations as $conv) {
1574              if (in_array($conv->id, [$ic2->id, $selfconversation->id])) {
1575                  $this->assertTrue($conv->isfavourite);
1576              } else {
1577                  $this->assertFalse($conv->isfavourite);
1578              }
1579          }
1580  
1581          // Now, get ONLY favourite conversations (including self-conversation).
1582          $conversations = api::get_conversations($user1->id, 0, 20, null, true);
1583          $this->assertCount(2, $conversations);
1584          foreach ($conversations as $conv) {
1585              if ($conv->type != api::MESSAGE_CONVERSATION_TYPE_SELF) {
1586                  $this->assertTrue($conv->isfavourite);
1587                  $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $conv->type);
1588                  $this->assertEquals($ic2->id, $conv->id);
1589              }
1590          }
1591  
1592          // Now, try ONLY favourites of type 'group'.
1593          $conversations = api::get_conversations($user1->id, 0, 20,
1594              api::MESSAGE_CONVERSATION_TYPE_GROUP, true);
1595          $this->assertEmpty($conversations);
1596  
1597          // And NO favourite conversations.
1598          $conversations = api::get_conversations($user1->id, 0, 20, null, false);
1599          $this->assertCount(5, $conversations);
1600          foreach ($conversations as $conv) {
1601              $this->assertFalse($conv->isfavourite);
1602              $this->assertNotEquals($ic2, $conv->id);
1603          }
1604      }
1605  
1606      /**
1607       * Test verifying the behaviour of get_conversations() when fetching favourite conversations.
1608       */
1609      public function test_get_conversations_favourite_conversations() {
1610          // Get a bunch of conversations, some group, some individual and in different states.
1611          list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
1612              $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
1613  
1614          // Try to get ONLY favourite conversations, when only self-conversation exist.
1615          $this->assertCount(1, api::get_conversations($user1->id, 0, 20, null, true));
1616  
1617          // Unstar self-conversation.
1618          $selfconversation = api::get_self_conversation($user1->id);
1619          api::unset_favourite_conversation($selfconversation->id, $user1->id);
1620  
1621          // Try to get ONLY favourite conversations, when no favourites exist.
1622          $this->assertEquals([], api::get_conversations($user1->id, 0, 20, null, true));
1623  
1624          // Try to get NO favourite conversations, when no favourites exist.
1625          $this->assertCount(7, api::get_conversations($user1->id, 0, 20, null, false));
1626  
1627          // Mark a few conversations as favourites.
1628          api::set_favourite_conversation($ic1->id, $user1->id);
1629          api::set_favourite_conversation($gc2->id, $user1->id);
1630          api::set_favourite_conversation($gc5->id, $user1->id);
1631          $favouriteids = [$ic1->id, $gc2->id, $gc5->id];
1632  
1633          // Get the conversations, first with no restrictions, confirming the favourite status of the conversations.
1634          $conversations = api::get_conversations($user1->id);
1635          $this->assertCount(7, $conversations);
1636          foreach ($conversations as $conv) {
1637              if (in_array($conv->id, $favouriteids)) {
1638                  $this->assertTrue($conv->isfavourite);
1639              } else {
1640                  $this->assertFalse($conv->isfavourite);
1641              }
1642          }
1643  
1644          // Now, get ONLY favourite conversations.
1645          $conversations = api::get_conversations($user1->id, 0, 20, null, true);
1646          $this->assertCount(3, $conversations);
1647          foreach ($conversations as $conv) {
1648              $this->assertTrue($conv->isfavourite);
1649              $this->assertNotFalse(array_search($conv->id, $favouriteids));
1650          }
1651  
1652          // Now, try ONLY favourites of type 'group'.
1653          $conversations = api::get_conversations($user1->id, 0, 20,
1654              api::MESSAGE_CONVERSATION_TYPE_GROUP, true);
1655          $this->assertCount(2, $conversations);
1656          foreach ($conversations as $conv) {
1657              $this->assertTrue($conv->isfavourite);
1658              $this->assertNotFalse(array_search($conv->id, [$gc2->id, $gc5->id]));
1659          }
1660  
1661          // And NO favourite conversations.
1662          $conversations = api::get_conversations($user1->id, 0, 20, null, false);
1663          $this->assertCount(4, $conversations);
1664          foreach ($conversations as $conv) {
1665              $this->assertFalse($conv->isfavourite);
1666              $this->assertFalse(array_search($conv->id, $favouriteids));
1667          }
1668      }
1669  
1670      /**
1671       * Test verifying get_conversations when there are users in a group and/or individual conversation. The reason this
1672       * test is performed is because we do not need as much data for group conversations (saving DB calls), so we want
1673       * to confirm this happens.
1674       */
1675      public function test_get_conversations_user_in_group_and_individual_chat() {
1676          $this->resetAfterTest();
1677  
1678          $user1 = self::getDataGenerator()->create_user();
1679          $user2 = self::getDataGenerator()->create_user();
1680          $user3 = self::getDataGenerator()->create_user();
1681  
1682          $conversation = api::create_conversation(
1683              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1684              [
1685                  $user1->id,
1686                  $user2->id
1687              ],
1688              'Individual conversation'
1689          );
1690  
1691          testhelper::send_fake_message_to_conversation($user1, $conversation->id);
1692  
1693          $conversation = api::create_conversation(
1694              api::MESSAGE_CONVERSATION_TYPE_GROUP,
1695              [
1696                  $user1->id,
1697                  $user2->id,
1698              ],
1699              'Group conversation'
1700          );
1701  
1702          testhelper::send_fake_message_to_conversation($user1, $conversation->id);
1703  
1704          api::create_contact_request($user1->id, $user2->id);
1705          api::create_contact_request($user1->id, $user3->id);
1706  
1707          $conversations = api::get_conversations($user2->id);
1708  
1709          $groupconversation = array_shift($conversations);
1710          $individualconversation = array_shift($conversations);
1711  
1712          $this->assertEquals('Group conversation', $groupconversation->name);
1713          $this->assertEquals('Individual conversation', $individualconversation->name);
1714  
1715          $this->assertCount(1, $groupconversation->members);
1716          $this->assertCount(1, $individualconversation->members);
1717  
1718          $groupmember = reset($groupconversation->members);
1719          $this->assertNull($groupmember->requirescontact);
1720          $this->assertNull($groupmember->canmessage);
1721          $this->assertEmpty($groupmember->contactrequests);
1722  
1723          $individualmember = reset($individualconversation->members);
1724          $this->assertNotNull($individualmember->requirescontact);
1725          $this->assertNotNull($individualmember->canmessage);
1726          $this->assertNotEmpty($individualmember->contactrequests);
1727      }
1728  
1729      /**
1730       * Test verifying that group linked conversations are returned and contain a subname matching the course name.
1731       */
1732      public function test_get_conversations_group_linked() {
1733          global $CFG, $DB;
1734  
1735          // Create some users.
1736          $user1 = self::getDataGenerator()->create_user();
1737          $user2 = self::getDataGenerator()->create_user();
1738          $user3 = self::getDataGenerator()->create_user();
1739  
1740          $course1 = $this->getDataGenerator()->create_course();
1741  
1742          // Create a group with a linked conversation and a valid image.
1743          $this->setAdminUser();
1744          $this->getDataGenerator()->enrol_user($user1->id, $course1->id);
1745          $this->getDataGenerator()->enrol_user($user2->id, $course1->id);
1746          $this->getDataGenerator()->enrol_user($user3->id, $course1->id);
1747          $group1 = $this->getDataGenerator()->create_group([
1748              'courseid' => $course1->id,
1749              'enablemessaging' => 1,
1750              'picturepath' => $CFG->dirroot . '/lib/tests/fixtures/gd-logo.png'
1751          ]);
1752  
1753          // Add users to group1.
1754          $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user1->id));
1755          $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user2->id));
1756  
1757          // Verify the group with the image works as expected.
1758          $conversations = api::get_conversations($user1->id);
1759          $this->assertEquals(2, $conversations[0]->membercount);
1760          $this->assertEquals($course1->shortname, $conversations[0]->subname);
1761          $groupimageurl = get_group_picture_url($group1, $group1->courseid, true);
1762          $this->assertEquals($groupimageurl, $conversations[0]->imageurl);
1763  
1764          // Create a group with a linked conversation and without any image.
1765          $group2 = $this->getDataGenerator()->create_group([
1766              'courseid' => $course1->id,
1767              'enablemessaging' => 1,
1768          ]);
1769  
1770          // Add users to group2.
1771          $this->getDataGenerator()->create_group_member(array('groupid' => $group2->id, 'userid' => $user2->id));
1772          $this->getDataGenerator()->create_group_member(array('groupid' => $group2->id, 'userid' => $user3->id));
1773  
1774          // Verify the group without any image works as expected too.
1775          $conversations = api::get_conversations($user3->id);
1776          // Consider first conversations is self-conversation.
1777          $this->assertEquals(2, $conversations[0]->membercount);
1778          $this->assertEquals($course1->shortname, $conversations[0]->subname);
1779          $this->assertEquals('https://www.example.com/moodle/theme/image.php/_s/boost/core/1/g/g1', $conversations[0]->imageurl);
1780  
1781          // Now, disable the conversation linked to the group and verify it's no longer returned.
1782          $DB->set_field('message_conversations', 'enabled', 0, ['id' => $conversations[0]->id]);
1783          $conversations = api::get_conversations($user3->id);
1784          $this->assertCount(1, $conversations);
1785      }
1786  
1787     /**
1788      * The data provider for get_conversations_mixed.
1789      *
1790      * This provides sets of data to for testing.
1791      * @return array
1792      */
1793     public function get_conversations_mixed_provider() {
1794         return array(
1795              'Test that conversations with messages contacts is correctly ordered.' => array(
1796                  'users' => array(
1797                      'user1',
1798                      'user2',
1799                      'user3',
1800                  ),
1801                  'contacts' => array(
1802                  ),
1803                  'messages' => array(
1804                      array(
1805                          'from'          => 'user1',
1806                          'to'            => 'user2',
1807                          'state'         => 'unread',
1808                          'subject'       => 'S1',
1809                      ),
1810                      array(
1811                          'from'          => 'user2',
1812                          'to'            => 'user1',
1813                          'state'         => 'unread',
1814                          'subject'       => 'S2',
1815                      ),
1816                      array(
1817                          'from'          => 'user1',
1818                          'to'            => 'user2',
1819                          'state'         => 'unread',
1820                          'timecreated'   => 0,
1821                          'subject'       => 'S3',
1822                      ),
1823                      array(
1824                          'from'          => 'user1',
1825                          'to'            => 'user3',
1826                          'state'         => 'read',
1827                          'timemodifier'  => 1,
1828                          'subject'       => 'S4',
1829                      ),
1830                      array(
1831                          'from'          => 'user3',
1832                          'to'            => 'user1',
1833                          'state'         => 'read',
1834                          'timemodifier'  => 1,
1835                          'subject'       => 'S5',
1836                      ),
1837                      array(
1838                          'from'          => 'user1',
1839                          'to'            => 'user3',
1840                          'state'         => 'read',
1841                          'timecreated'   => 0,
1842                          'subject'       => 'S6',
1843                      ),
1844                  ),
1845                  'expectations' => array(
1846                      'user1' => array(
1847                          // User1 has conversed most recently with user3. The most recent message is M5.
1848                          array(
1849                              'messageposition'   => 0,
1850                              'with'              => 'user3',
1851                              'subject'           => '<p>S5</p>',
1852                              'unreadcount'       => 0,
1853                          ),
1854                          // User1 has also conversed with user2. The most recent message is S2.
1855                          array(
1856                              'messageposition'   => 1,
1857                              'with'              => 'user2',
1858                              'subject'           => '<p>S2</p>',
1859                              'unreadcount'       => 1,
1860                          ),
1861                      ),
1862                      'user2' => array(
1863                          // User2 has only conversed with user1. Their most recent shared message was S2.
1864                          array(
1865                              'messageposition'   => 0,
1866                              'with'              => 'user1',
1867                              'subject'           => '<p>S2</p>',
1868                              'unreadcount'       => 2,
1869                          ),
1870                      ),
1871                      'user3' => array(
1872                          // User3 has only conversed with user1. Their most recent shared message was S5.
1873                          array(
1874                              'messageposition'   => 0,
1875                              'with'              => 'user1',
1876                              'subject'           => '<p>S5</p>',
1877                              'unreadcount'       => 0,
1878                          ),
1879                      ),
1880                  ),
1881              ),
1882              'Test conversations with a single user, where some messages are read and some are not.' => array(
1883                  'users' => array(
1884                      'user1',
1885                      'user2',
1886                  ),
1887                  'contacts' => array(
1888                  ),
1889                  'messages' => array(
1890                      array(
1891                          'from'          => 'user1',
1892                          'to'            => 'user2',
1893                          'state'         => 'read',
1894                          'subject'       => 'S1',
1895                      ),
1896                      array(
1897                          'from'          => 'user2',
1898                          'to'            => 'user1',
1899                          'state'         => 'read',
1900                          'subject'       => 'S2',
1901                      ),
1902                      array(
1903                          'from'          => 'user1',
1904                          'to'            => 'user2',
1905                          'state'         => 'unread',
1906                          'timemodifier'  => 1,
1907                          'subject'       => 'S3',
1908                      ),
1909                      array(
1910                          'from'          => 'user1',
1911                          'to'            => 'user2',
1912                          'state'         => 'unread',
1913                          'timemodifier'  => 1,
1914                          'subject'       => 'S4',
1915                      ),
1916                  ),
1917                  'expectations' => array(
1918                      // The most recent message between user1 and user2 was S4.
1919                      'user1' => array(
1920                          array(
1921                              'messageposition'   => 0,
1922                              'with'              => 'user2',
1923                              'subject'           => '<p>S4</p>',
1924                              'unreadcount'       => 0,
1925                          ),
1926                      ),
1927                      'user2' => array(
1928                          // The most recent message between user1 and user2 was S4.
1929                          array(
1930                              'messageposition'   => 0,
1931                              'with'              => 'user1',
1932                              'subject'           => '<p>S4</p>',
1933                              'unreadcount'       => 2,
1934                          ),
1935                      ),
1936                  ),
1937              ),
1938              'Test conversations with a single user, where some messages are read and some are not, and messages ' .
1939              'are out of order' => array(
1940              // This can happen through a combination of factors including multi-master DB replication with messages
1941              // read somehow (e.g. API).
1942                  'users' => array(
1943                      'user1',
1944                      'user2',
1945                  ),
1946                  'contacts' => array(
1947                  ),
1948                  'messages' => array(
1949                      array(
1950                          'from'          => 'user1',
1951                          'to'            => 'user2',
1952                          'state'         => 'read',
1953                          'subject'       => 'S1',
1954                          'timemodifier'  => 1,
1955                      ),
1956                      array(
1957                          'from'          => 'user2',
1958                          'to'            => 'user1',
1959                          'state'         => 'read',
1960                          'subject'       => 'S2',
1961                          'timemodifier'  => 2,
1962                      ),
1963                      array(
1964                          'from'          => 'user1',
1965                          'to'            => 'user2',
1966                          'state'         => 'unread',
1967                          'subject'       => 'S3',
1968                      ),
1969                      array(
1970                          'from'          => 'user1',
1971                          'to'            => 'user2',
1972                          'state'         => 'unread',
1973                          'subject'       => 'S4',
1974                      ),
1975                  ),
1976                  'expectations' => array(
1977                      // The most recent message between user1 and user2 was S2, even though later IDs have not been read.
1978                      'user1' => array(
1979                          array(
1980                              'messageposition'   => 0,
1981                              'with'              => 'user2',
1982                              'subject'           => '<p>S2</p>',
1983                              'unreadcount'       => 0,
1984                          ),
1985                      ),
1986                      'user2' => array(
1987                          array(
1988                              'messageposition'   => 0,
1989                              'with'              => 'user1',
1990                              'subject'           => '<p>S2</p>',
1991                              'unreadcount'       => 2
1992                          ),
1993                      ),
1994                  ),
1995              ),
1996              'Test unread message count is correct for both users' => array(
1997                  'users' => array(
1998                      'user1',
1999                      'user2',
2000                  ),
2001                  'contacts' => array(
2002                  ),
2003                  'messages' => array(
2004                      array(
2005                          'from'          => 'user1',
2006                          'to'            => 'user2',
2007                          'state'         => 'read',
2008                          'subject'       => 'S1',
2009                          'timemodifier'  => 1,
2010                      ),
2011                      array(
2012                          'from'          => 'user2',
2013                          'to'            => 'user1',
2014                          'state'         => 'read',
2015                          'subject'       => 'S2',
2016                          'timemodifier'  => 2,
2017                      ),
2018                      array(
2019                          'from'          => 'user1',
2020                          'to'            => 'user2',
2021                          'state'         => 'read',
2022                          'subject'       => 'S3',
2023                          'timemodifier'  => 3,
2024                      ),
2025                      array(
2026                          'from'          => 'user1',
2027                          'to'            => 'user2',
2028                          'state'         => 'read',
2029                          'subject'       => 'S4',
2030                          'timemodifier'  => 4,
2031                      ),
2032                      array(
2033                          'from'          => 'user1',
2034                          'to'            => 'user2',
2035                          'state'         => 'unread',
2036                          'subject'       => 'S5',
2037                          'timemodifier'  => 5,
2038                      ),
2039                      array(
2040                          'from'          => 'user2',
2041                          'to'            => 'user1',
2042                          'state'         => 'unread',
2043                          'subject'       => 'S6',
2044                          'timemodifier'  => 6,
2045                      ),
2046                      array(
2047                          'from'          => 'user1',
2048                          'to'            => 'user2',
2049                          'state'         => 'unread',
2050                          'subject'       => 'S7',
2051                          'timemodifier'  => 7,
2052                      ),
2053                      array(
2054                          'from'          => 'user1',
2055                          'to'            => 'user2',
2056                          'state'         => 'unread',
2057                          'subject'       => 'S8',
2058                          'timemodifier'  => 8,
2059                      ),
2060                  ),
2061                  'expectations' => array(
2062                      // The most recent message between user1 and user2 was S2, even though later IDs have not been read.
2063                      'user1' => array(
2064                          array(
2065                              'messageposition'   => 0,
2066                              'with'              => 'user2',
2067                              'subject'           => '<p>S8</p>',
2068                              'unreadcount'       => 1,
2069                          ),
2070                      ),
2071                      'user2' => array(
2072                          array(
2073                              'messageposition'   => 0,
2074                              'with'              => 'user1',
2075                              'subject'           => '<p>S8</p>',
2076                              'unreadcount'       => 3,
2077                          ),
2078                      ),
2079                  ),
2080              ),
2081          );
2082      }
2083  
2084      /**
2085       * Test that creation can't create the same conversation twice for 1:1 conversations.
2086       */
2087      public function test_create_conversation_duplicate_conversations() {
2088          global $DB;
2089          $user1 = $this::getDataGenerator()->create_user();
2090  
2091          api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_SELF, [$user1->id]);
2092          api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_SELF, [$user1->id]);
2093  
2094          $convhash = helper::get_conversation_hash([$user1->id]);
2095          $countconversations = $DB->count_records('message_conversations', ['convhash' => $convhash]);
2096          $this->assertEquals(1, $countconversations);
2097          $this->assertNotEmpty($conversation = api::get_self_conversation($user1->id));
2098      }
2099  
2100      /**
2101       * Test get_conversations with a mixture of messages.
2102       *
2103       * @dataProvider get_conversations_mixed_provider
2104       * @param array $usersdata The list of users to create for this test.
2105       * @param array $messagesdata The list of messages to create.
2106       * @param array $expectations The list of expected outcomes.
2107       */
2108      public function test_get_conversations_mixed($usersdata, $contacts, $messagesdata, $expectations) {
2109          global $DB;
2110  
2111          // Create all of the users.
2112          $users = array();
2113          foreach ($usersdata as $username) {
2114              $users[$username] = $this->getDataGenerator()->create_user(array('username' => $username));
2115          }
2116  
2117          foreach ($contacts as $username => $contact) {
2118              foreach ($contact as $contactname => $blocked) {
2119                  $record = new \stdClass();
2120                  $record->userid     = $users[$username]->id;
2121                  $record->contactid  = $users[$contactname]->id;
2122                  $record->blocked    = $blocked;
2123                  $record->id = $DB->insert_record('message_contacts', $record);
2124              }
2125          }
2126  
2127          $defaulttimecreated = time();
2128          foreach ($messagesdata as $messagedata) {
2129              $from       = $users[$messagedata['from']];
2130              $to         = $users[$messagedata['to']];
2131              $subject    = $messagedata['subject'];
2132  
2133              if (isset($messagedata['state']) && $messagedata['state'] == 'unread') {
2134                  $messageid = $this->send_fake_message($from, $to, $subject);
2135              } else {
2136                  // If there is no state, or the state is not 'unread', assume the message is read.
2137                  $messageid = message_post_message($from, $to, $subject, FORMAT_PLAIN);
2138              }
2139  
2140              $updatemessage = new \stdClass();
2141              $updatemessage->id = $messageid;
2142              if (isset($messagedata['timecreated'])) {
2143                  $updatemessage->timecreated = $messagedata['timecreated'];
2144              } else if (isset($messagedata['timemodifier'])) {
2145                  $updatemessage->timecreated = $defaulttimecreated + $messagedata['timemodifier'];
2146              } else {
2147                  $updatemessage->timecreated = $defaulttimecreated;
2148              }
2149  
2150              $DB->update_record('messages', $updatemessage);
2151          }
2152  
2153          foreach ($expectations as $username => $data) {
2154              // Get the recent conversations for the specified user.
2155              $user = $users[$username];
2156              $conversations = array_values(api::get_conversations($user->id));
2157              foreach ($data as $expectation) {
2158                  $otheruser = $users[$expectation['with']];
2159                  $conversation = $conversations[$expectation['messageposition']];
2160                  $this->assertEquals($otheruser->id, $conversation->members[$otheruser->id]->id);
2161                  $this->assertEquals($expectation['subject'], $conversation->messages[0]->text);
2162                  $this->assertEquals($expectation['unreadcount'], $conversation->unreadcount);
2163              }
2164          }
2165      }
2166  
2167      /**
2168       * Tests retrieving user contacts.
2169       */
2170      public function test_get_user_contacts() {
2171          // Create some users.
2172          $user1 = self::getDataGenerator()->create_user();
2173  
2174          // Set as the user.
2175          $this->setUser($user1);
2176  
2177          $user2 = new \stdClass();
2178          $user2->firstname = 'User';
2179          $user2->lastname = 'A';
2180          $user2 = self::getDataGenerator()->create_user($user2);
2181  
2182          $user3 = new \stdClass();
2183          $user3->firstname = 'User';
2184          $user3->lastname = 'B';
2185          $user3 = self::getDataGenerator()->create_user($user3);
2186  
2187          $user4 = new \stdClass();
2188          $user4->firstname = 'User';
2189          $user4->lastname = 'C';
2190          $user4 = self::getDataGenerator()->create_user($user4);
2191  
2192          $user5 = new \stdClass();
2193          $user5->firstname = 'User';
2194          $user5->lastname = 'D';
2195          $user5 = self::getDataGenerator()->create_user($user5);
2196  
2197          // Add some users as contacts.
2198          api::add_contact($user1->id, $user2->id);
2199          api::add_contact($user1->id, $user3->id);
2200          api::add_contact($user1->id, $user4->id);
2201  
2202          // Retrieve the contacts.
2203          $contacts = api::get_user_contacts($user1->id);
2204  
2205          // Confirm the data is correct.
2206          $this->assertEquals(3, count($contacts));
2207  
2208          ksort($contacts);
2209  
2210          $contact1 = array_shift($contacts);
2211          $contact2 = array_shift($contacts);
2212          $contact3 = array_shift($contacts);
2213  
2214          $this->assertEquals($user2->id, $contact1->id);
2215          $this->assertEquals(fullname($user2), $contact1->fullname);
2216          $this->assertTrue($contact1->iscontact);
2217  
2218          $this->assertEquals($user3->id, $contact2->id);
2219          $this->assertEquals(fullname($user3), $contact2->fullname);
2220          $this->assertTrue($contact2->iscontact);
2221  
2222          $this->assertEquals($user4->id, $contact3->id);
2223          $this->assertEquals(fullname($user4), $contact3->fullname);
2224          $this->assertTrue($contact3->iscontact);
2225      }
2226  
2227      /**
2228       * Tests retrieving conversation messages.
2229       */
2230      public function test_get_conversation_messages() {
2231          // Create some users.
2232          $user1 = self::getDataGenerator()->create_user();
2233          $user2 = self::getDataGenerator()->create_user();
2234  
2235          // Create conversation.
2236          $conversation = api::create_conversation(
2237              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
2238              [$user1->id, $user2->id]
2239          );
2240  
2241          // The person doing the search.
2242          $this->setUser($user1);
2243  
2244          // Send some messages back and forth.
2245          $time = 1;
2246          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time + 1);
2247          testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 2);
2248          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Writing PHPUnit tests!', $time + 3);
2249          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Word.', $time + 4);
2250  
2251          // Retrieve the messages.
2252          $convmessages = api::get_conversation_messages($user1->id, $conversation->id);
2253  
2254          // Confirm the conversation id is correct.
2255          $this->assertEquals($conversation->id, $convmessages['id']);
2256  
2257          // Confirm the message data is correct.
2258          $messages = $convmessages['messages'];
2259          $this->assertEquals(4, count($messages));
2260          $message1 = $messages[0];
2261          $message2 = $messages[1];
2262          $message3 = $messages[2];
2263          $message4 = $messages[3];
2264  
2265          $this->assertEquals($user1->id, $message1->useridfrom);
2266          $this->assertStringContainsString('Yo!', $message1->text);
2267  
2268          $this->assertEquals($user2->id, $message2->useridfrom);
2269          $this->assertStringContainsString('Sup mang?', $message2->text);
2270  
2271          $this->assertEquals($user1->id, $message3->useridfrom);
2272          $this->assertStringContainsString('Writing PHPUnit tests!', $message3->text);
2273  
2274          $this->assertEquals($user1->id, $message4->useridfrom);
2275          $this->assertStringContainsString('Word.', $message4->text);
2276  
2277          // Confirm the members data is correct.
2278          $members = $convmessages['members'];
2279          $this->assertEquals(2, count($members));
2280      }
2281  
2282      /**
2283       * Tests retrieving group conversation messages.
2284       */
2285      public function test_get_group_conversation_messages() {
2286          // Create some users.
2287          $user1 = self::getDataGenerator()->create_user();
2288          $user2 = self::getDataGenerator()->create_user();
2289          $user3 = self::getDataGenerator()->create_user();
2290          $user4 = self::getDataGenerator()->create_user();
2291  
2292          // Create group conversation.
2293          $conversation = api::create_conversation(
2294              api::MESSAGE_CONVERSATION_TYPE_GROUP,
2295              [$user1->id, $user2->id, $user3->id, $user4->id]
2296          );
2297  
2298          // The person doing the search.
2299          $this->setUser($user1);
2300  
2301          // Send some messages back and forth.
2302          $time = 1;
2303          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time + 1);
2304          testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 2);
2305          testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Writing PHPUnit tests!', $time + 3);
2306          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Word.', $time + 4);
2307          testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Yeah!', $time + 5);
2308  
2309          // Retrieve the messages.
2310          $convmessages = api::get_conversation_messages($user1->id, $conversation->id);
2311  
2312          // Confirm the conversation id is correct.
2313          $this->assertEquals($conversation->id, $convmessages['id']);
2314  
2315          // Confirm the message data is correct.
2316          $messages = $convmessages['messages'];
2317          $this->assertEquals(5, count($messages));
2318  
2319          $message1 = $messages[0];
2320          $message2 = $messages[1];
2321          $message3 = $messages[2];
2322          $message4 = $messages[3];
2323          $message5 = $messages[4];
2324  
2325          $this->assertEquals($user1->id, $message1->useridfrom);
2326          $this->assertStringContainsString('Yo!', $message1->text);
2327  
2328          $this->assertEquals($user2->id, $message2->useridfrom);
2329          $this->assertStringContainsString('Sup mang?', $message2->text);
2330  
2331          $this->assertEquals($user3->id, $message3->useridfrom);
2332          $this->assertStringContainsString('Writing PHPUnit tests!', $message3->text);
2333  
2334          $this->assertEquals($user1->id, $message4->useridfrom);
2335          $this->assertStringContainsString('Word.', $message4->text);
2336  
2337          $this->assertEquals($user2->id, $message5->useridfrom);
2338          $this->assertStringContainsString('Yeah!', $message5->text);
2339  
2340          // Confirm the members data is correct.
2341          $members = $convmessages['members'];
2342          $this->assertEquals(3, count($members));
2343      }
2344  
2345      /**
2346       * Test verifying the sorting param for get_conversation_messages is respected().
2347       */
2348      public function test_get_conversation_messages_sorting() {
2349          // Create some users.
2350          $user1 = self::getDataGenerator()->create_user();
2351          $user2 = self::getDataGenerator()->create_user();
2352          $user3 = self::getDataGenerator()->create_user();
2353  
2354          // Create conversations - 1 group and 1 individual.
2355          $conversation = api::create_conversation(
2356              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
2357              [$user1->id, $user2->id]
2358          );
2359          $conversation2 = api::create_conversation(
2360              api::MESSAGE_CONVERSATION_TYPE_GROUP,
2361              [$user1->id, $user2->id, $user3->id]
2362          );
2363  
2364          // Send some messages back and forth.
2365          $time = 1;
2366          $m1id = testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time + 1);
2367          $m2id = testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 2);
2368          $m3id = testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Writing PHPUnit tests!', $time + 3);
2369          $m4id = testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Word.', $time + 4);
2370  
2371          $gm1id = testhelper::send_fake_message_to_conversation($user1, $conversation2->id, 'Yo!', $time + 1);
2372          $gm2id = testhelper::send_fake_message_to_conversation($user2, $conversation2->id, 'Sup mang?', $time + 2);
2373          $gm3id = testhelper::send_fake_message_to_conversation($user3, $conversation2->id, 'Writing PHPUnit tests!', $time + 3);
2374          $gm4id = testhelper::send_fake_message_to_conversation($user1, $conversation2->id, 'Word.', $time + 4);
2375  
2376          // The person doing the search.
2377          $this->setUser($user1);
2378  
2379          // Retrieve the messages using default sort ('timecreated ASC') and verify ordering.
2380          $convmessages = api::get_conversation_messages($user1->id, $conversation->id);
2381          $messages = $convmessages['messages'];
2382          $this->assertEquals($m1id, $messages[0]->id);
2383          $this->assertEquals($m2id, $messages[1]->id);
2384          $this->assertEquals($m3id, $messages[2]->id);
2385          $this->assertEquals($m4id, $messages[3]->id);
2386  
2387          // Retrieve the messages without specifying DESC sort ordering, and verify ordering.
2388          $convmessages = api::get_conversation_messages($user1->id, $conversation->id, 0, 0, 'timecreated DESC');
2389          $messages = $convmessages['messages'];
2390          $this->assertEquals($m1id, $messages[3]->id);
2391          $this->assertEquals($m2id, $messages[2]->id);
2392          $this->assertEquals($m3id, $messages[1]->id);
2393          $this->assertEquals($m4id, $messages[0]->id);
2394  
2395          // Retrieve the messages using default sort ('timecreated ASC') and verify ordering.
2396          $convmessages = api::get_conversation_messages($user1->id, $conversation2->id);
2397          $messages = $convmessages['messages'];
2398          $this->assertEquals($gm1id, $messages[0]->id);
2399          $this->assertEquals($gm2id, $messages[1]->id);
2400          $this->assertEquals($gm3id, $messages[2]->id);
2401          $this->assertEquals($gm4id, $messages[3]->id);
2402  
2403          // Retrieve the messages without specifying DESC sort ordering, and verify ordering.
2404          $convmessages = api::get_conversation_messages($user1->id, $conversation2->id, 0, 0, 'timecreated DESC');
2405          $messages = $convmessages['messages'];
2406          $this->assertEquals($gm1id, $messages[3]->id);
2407          $this->assertEquals($gm2id, $messages[2]->id);
2408          $this->assertEquals($gm3id, $messages[1]->id);
2409          $this->assertEquals($gm4id, $messages[0]->id);
2410      }
2411  
2412      /**
2413       * Test retrieving conversation messages by providing a minimum timecreated value.
2414       */
2415      public function test_get_conversation_messages_time_from_only() {
2416          // Create some users.
2417          $user1 = self::getDataGenerator()->create_user();
2418          $user2 = self::getDataGenerator()->create_user();
2419          $user3 = self::getDataGenerator()->create_user();
2420          $user4 = self::getDataGenerator()->create_user();
2421  
2422          // Create group conversation.
2423          $conversation = api::create_conversation(
2424              api::MESSAGE_CONVERSATION_TYPE_GROUP,
2425              [$user1->id, $user2->id, $user3->id, $user4->id]
2426          );
2427  
2428          // The person doing the search.
2429          $this->setUser($user1);
2430  
2431          // Send some messages back and forth.
2432          $time = 1;
2433          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2434          testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2435          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2436          testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2437  
2438          // Retrieve the messages from $time, which should be all of them.
2439          $convmessages = api::get_conversation_messages($user1->id, $conversation->id, 0, 0, 'timecreated ASC', $time);
2440  
2441          // Confirm the conversation id is correct.
2442          $this->assertEquals($conversation->id, $convmessages['id']);
2443  
2444          // Confirm the message data is correct.
2445          $messages = $convmessages['messages'];
2446          $this->assertEquals(4, count($messages));
2447  
2448          $message1 = $messages[0];
2449          $message2 = $messages[1];
2450          $message3 = $messages[2];
2451          $message4 = $messages[3];
2452  
2453          $this->assertStringContainsString('Message 1', $message1->text);
2454          $this->assertStringContainsString('Message 2', $message2->text);
2455          $this->assertStringContainsString('Message 3', $message3->text);
2456          $this->assertStringContainsString('Message 4', $message4->text);
2457  
2458          // Confirm the members data is correct.
2459          $members = $convmessages['members'];
2460          $this->assertEquals(3, count($members));
2461  
2462          // Retrieve the messages from $time + 3, which should only be the 2 last messages.
2463          $convmessages = api::get_conversation_messages($user1->id, $conversation->id, 0, 0,
2464              'timecreated ASC', $time + 3);
2465  
2466          // Confirm the conversation id is correct.
2467          $this->assertEquals($conversation->id, $convmessages['id']);
2468  
2469          // Confirm the message data is correct.
2470          $messages = $convmessages['messages'];
2471          $this->assertEquals(2, count($messages));
2472  
2473          $message1 = $messages[0];
2474          $message2 = $messages[1];
2475  
2476          $this->assertStringContainsString('Message 3', $message1->text);
2477          $this->assertStringContainsString('Message 4', $message2->text);
2478  
2479          // Confirm the members data is correct.
2480          $members = $convmessages['members'];
2481          $this->assertEquals(2, count($members));
2482      }
2483  
2484      /**
2485       * Test retrieving conversation messages by providing a maximum timecreated value.
2486       */
2487      public function test_get_conversation_messages_time_to_only() {
2488          // Create some users.
2489          $user1 = self::getDataGenerator()->create_user();
2490          $user2 = self::getDataGenerator()->create_user();
2491          $user3 = self::getDataGenerator()->create_user();
2492          $user4 = self::getDataGenerator()->create_user();
2493  
2494          // Create group conversation.
2495          $conversation = api::create_conversation(
2496              api::MESSAGE_CONVERSATION_TYPE_GROUP,
2497              [$user1->id, $user2->id, $user3->id, $user4->id]
2498          );
2499  
2500          // The person doing the search.
2501          $this->setUser($user1);
2502  
2503          // Send some messages back and forth.
2504          $time = 1;
2505          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2506          testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2507          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2508          testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2509  
2510          // Retrieve the messages up until $time + 4, which should be all of them.
2511          $convmessages = api::get_conversation_messages($user1->id, $conversation->id, 0, 0, 'timecreated ASC',
2512              0, $time + 4);
2513  
2514          // Confirm the conversation id is correct.
2515          $this->assertEquals($conversation->id, $convmessages['id']);
2516  
2517          // Confirm the message data is correct.
2518          $messages = $convmessages['messages'];
2519          $this->assertEquals(4, count($messages));
2520  
2521          $message1 = $messages[0];
2522          $message2 = $messages[1];
2523          $message3 = $messages[2];
2524          $message4 = $messages[3];
2525  
2526          $this->assertStringContainsString('Message 1', $message1->text);
2527          $this->assertStringContainsString('Message 2', $message2->text);
2528          $this->assertStringContainsString('Message 3', $message3->text);
2529          $this->assertStringContainsString('Message 4', $message4->text);
2530  
2531          // Confirm the members data is correct.
2532          $members = $convmessages['members'];
2533          $this->assertEquals(3, count($members));
2534  
2535          // Retrieve the messages up until $time + 2, which should be the first two.
2536          $convmessages = api::get_conversation_messages($user1->id, $conversation->id, 0, 0, 'timecreated ASC',
2537              0, $time + 2);
2538  
2539          // Confirm the conversation id is correct.
2540          $this->assertEquals($conversation->id, $convmessages['id']);
2541  
2542          // Confirm the message data is correct.
2543          $messages = $convmessages['messages'];
2544          $this->assertEquals(2, count($messages));
2545  
2546          $message1 = $messages[0];
2547          $message2 = $messages[1];
2548  
2549          $this->assertStringContainsString('Message 1', $message1->text);
2550          $this->assertStringContainsString('Message 2', $message2->text);
2551  
2552          // Confirm the members data is correct.
2553          $members = $convmessages['members'];
2554          $this->assertEquals(2, count($members));
2555      }
2556  
2557      /**
2558       * Test retrieving conversation messages by providing a minimum and maximum timecreated value.
2559       */
2560      public function test_get_conversation_messages_time_from_and_to() {
2561          // Create some users.
2562          $user1 = self::getDataGenerator()->create_user();
2563          $user2 = self::getDataGenerator()->create_user();
2564          $user3 = self::getDataGenerator()->create_user();
2565          $user4 = self::getDataGenerator()->create_user();
2566  
2567          // Create group conversation.
2568          $conversation = api::create_conversation(
2569              api::MESSAGE_CONVERSATION_TYPE_GROUP,
2570              [$user1->id, $user2->id, $user3->id, $user4->id]
2571          );
2572  
2573          // The person doing the search.
2574          $this->setUser($user1);
2575  
2576          // Send some messages back and forth.
2577          $time = 1;
2578          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2579          testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2580          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2581          testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2582  
2583          // Retrieve the messages from $time + 2 up until $time + 3, which should be 2nd and 3rd message.
2584          $convmessages = api::get_conversation_messages($user1->id, $conversation->id, 0, 0,
2585              'timecreated ASC', $time + 2, $time + 3);
2586  
2587          // Confirm the conversation id is correct.
2588          $this->assertEquals($conversation->id, $convmessages['id']);
2589  
2590          // Confirm the message data is correct.
2591          $messages = $convmessages['messages'];
2592          $this->assertEquals(2, count($messages));
2593  
2594          $message1 = $messages[0];
2595          $message2 = $messages[1];
2596  
2597          $this->assertStringContainsString('Message 2', $message1->text);
2598          $this->assertStringContainsString('Message 3', $message2->text);
2599  
2600          // Confirm the members data is correct.
2601          $members = $convmessages['members'];
2602          $this->assertEquals(2, count($members));
2603      }
2604  
2605  
2606      /**
2607       * Test retrieving conversation messages by providing a limitfrom value.
2608       */
2609      public function test_get_conversation_messages_limitfrom_only() {
2610          // Create some users.
2611          $user1 = self::getDataGenerator()->create_user();
2612          $user2 = self::getDataGenerator()->create_user();
2613          $user3 = self::getDataGenerator()->create_user();
2614          $user4 = self::getDataGenerator()->create_user();
2615  
2616          // Create group conversation.
2617          $conversation = api::create_conversation(
2618              api::MESSAGE_CONVERSATION_TYPE_GROUP,
2619              [$user1->id, $user2->id, $user3->id, $user4->id]
2620          );
2621  
2622          // The person doing the search.
2623          $this->setUser($user1);
2624  
2625          // Send some messages back and forth.
2626          $time = 1;
2627          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2628          testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2629          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2630          testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2631  
2632          // Retrieve the messages from $time, which should be all of them.
2633          $convmessages = api::get_conversation_messages($user1->id, $conversation->id, 2);
2634  
2635          // Confirm the conversation id is correct.
2636          $messages = $convmessages['messages'];
2637          $this->assertEquals($conversation->id, $convmessages['id']);
2638  
2639          // Confirm the message data is correct.
2640          $this->assertEquals(2, count($messages));
2641  
2642          $message1 = $messages[0];
2643          $message2 = $messages[1];
2644  
2645          $this->assertStringContainsString('Message 3', $message1->text);
2646          $this->assertStringContainsString('Message 4', $message2->text);
2647  
2648          // Confirm the members data is correct.
2649          $members = $convmessages['members'];
2650          $this->assertEquals(2, count($members));
2651      }
2652  
2653      /**
2654       * Test retrieving conversation messages by providing a limitnum value.
2655       */
2656      public function test_get_conversation_messages_limitnum() {
2657          // Create some users.
2658          $user1 = self::getDataGenerator()->create_user();
2659          $user2 = self::getDataGenerator()->create_user();
2660          $user3 = self::getDataGenerator()->create_user();
2661          $user4 = self::getDataGenerator()->create_user();
2662  
2663          // Create group conversation.
2664          $conversation = api::create_conversation(
2665              api::MESSAGE_CONVERSATION_TYPE_GROUP,
2666              [$user1->id, $user2->id, $user3->id, $user4->id]
2667          );
2668  
2669          // The person doing the search.
2670          $this->setUser($user1);
2671  
2672          // Send some messages back and forth.
2673          $time = 1;
2674          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
2675          testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
2676          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
2677          testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
2678  
2679          // Retrieve the messages from $time, which should be all of them.
2680          $convmessages = api::get_conversation_messages($user1->id, $conversation->id, 2, 1);
2681  
2682          // Confirm the conversation id is correct.
2683          $messages = $convmessages['messages'];
2684          $this->assertEquals($conversation->id, $convmessages['id']);
2685  
2686          // Confirm the message data is correct.
2687          $messages = $convmessages['messages'];
2688          $this->assertEquals(1, count($messages));
2689  
2690          $message1 = $messages[0];
2691  
2692          $this->assertStringContainsString('Message 3', $message1->text);
2693  
2694          // Confirm the members data is correct.
2695          $members = $convmessages['members'];
2696          $this->assertEquals(1, count($members));
2697      }
2698  
2699      /**
2700       * Tests retrieving most recent conversation message.
2701       */
2702      public function test_get_most_recent_conversation_message() {
2703          // Create some users.
2704          $user1 = self::getDataGenerator()->create_user();
2705          $user2 = self::getDataGenerator()->create_user();
2706          $user3 = self::getDataGenerator()->create_user();
2707  
2708          // Create group conversation.
2709          $conversation = api::create_conversation(
2710              api::MESSAGE_CONVERSATION_TYPE_GROUP,
2711              [$user1->id, $user2->id, $user3->id]
2712          );
2713  
2714          // The person getting the most recent conversation message.
2715          $this->setUser($user1);
2716  
2717          // Send some messages back and forth.
2718          $time = 1;
2719          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time + 1);
2720          testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Sup mang?', $time + 2);
2721          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Writing PHPUnit tests!', $time + 3);
2722          testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Word.', $time + 4);
2723  
2724          // Retrieve the most recent messages.
2725          $message = api::get_most_recent_conversation_message($conversation->id, $user1->id);
2726  
2727          // Check the results are correct.
2728          $this->assertEquals($user2->id, $message->useridfrom);
2729          $this->assertStringContainsString('Word.', $message->text);
2730      }
2731  
2732      /**
2733       * Tests checking if a user can mark all messages as read.
2734       */
2735      public function test_can_mark_all_messages_as_read() {
2736          // Set as the admin.
2737          $this->setAdminUser();
2738  
2739          // Create some users.
2740          $user1 = self::getDataGenerator()->create_user();
2741          $user2 = self::getDataGenerator()->create_user();
2742          $user3 = self::getDataGenerator()->create_user();
2743  
2744          // Send some messages back and forth.
2745          $time = 1;
2746          $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
2747          $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
2748          $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
2749          $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
2750  
2751          $conversationid = api::get_conversation_between_users([$user1->id, $user2->id]);
2752  
2753          // The admin can do anything.
2754          $this->assertTrue(api::can_mark_all_messages_as_read($user1->id, $conversationid));
2755  
2756          // Set as the user 1.
2757          $this->setUser($user1);
2758  
2759          // The user can mark the messages as he is in the conversation.
2760          $this->assertTrue(api::can_mark_all_messages_as_read($user1->id, $conversationid));
2761  
2762          // User 1 can not mark the messages read for user 2.
2763          $this->assertFalse(api::can_mark_all_messages_as_read($user2->id, $conversationid));
2764  
2765          // This user is not a part of the conversation.
2766          $this->assertFalse(api::can_mark_all_messages_as_read($user3->id, $conversationid));
2767      }
2768  
2769      /**
2770       * Tests checking if a user can delete a conversation.
2771       */
2772      public function test_can_delete_conversation() {
2773          // Set as the admin.
2774          $this->setAdminUser();
2775  
2776          // Create some users.
2777          $user1 = self::getDataGenerator()->create_user();
2778          $user2 = self::getDataGenerator()->create_user();
2779  
2780          // Send some messages back and forth.
2781          $time = 1;
2782          $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
2783          $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
2784          $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
2785          $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
2786  
2787          $conversationid = api::get_conversation_between_users([$user1->id, $user2->id]);
2788  
2789          // The admin can do anything.
2790          $this->assertTrue(api::can_delete_conversation($user1->id, $conversationid));
2791  
2792          // Set as the user 1.
2793          $this->setUser($user1);
2794  
2795          // They can delete their own messages.
2796          $this->assertTrue(api::can_delete_conversation($user1->id, $conversationid));
2797  
2798          // They can't delete someone elses.
2799          $this->assertFalse(api::can_delete_conversation($user2->id, $conversationid));
2800      }
2801  
2802      /**
2803       * Tests deleting a conversation by conversation id.
2804       */
2805      public function test_delete_conversation_by_id() {
2806          global $DB;
2807  
2808          // Create some users.
2809          $user1 = self::getDataGenerator()->create_user();
2810          $user2 = self::getDataGenerator()->create_user();
2811  
2812          // The person doing the search.
2813          $this->setUser($user1);
2814  
2815          // Get self-conversation.
2816          $sc1 = api::get_self_conversation($user1->id);
2817          $sc2 = api::get_self_conversation($user2->id);
2818  
2819          // Send some messages back and forth.
2820          $time = 1;
2821          $m1id = $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1);
2822          $m2id = $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2);
2823          $m3id = $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3);
2824          $m4id = $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4);
2825          $m5id = testhelper::send_fake_message_to_conversation($user1, $sc1->id, 'Hi to myself!', $time + 5);
2826          $m6id = testhelper::send_fake_message_to_conversation($user2, $sc2->id, 'I am talking with myself', $time + 6);
2827  
2828          $conversationid = api::get_conversation_between_users([$user1->id, $user2->id]);
2829  
2830          // Delete the individual conversation between user1 and user2 (only for user1).
2831          api::delete_conversation_by_id($user1->id, $conversationid);
2832  
2833          $muas = $DB->get_records('message_user_actions', array(), 'timecreated ASC');
2834          $this->assertCount(4, $muas);
2835          // Sort by id.
2836          ksort($muas);
2837  
2838          $mua1 = array_shift($muas);
2839          $mua2 = array_shift($muas);
2840          $mua3 = array_shift($muas);
2841          $mua4 = array_shift($muas);
2842  
2843          $this->assertEquals($user1->id, $mua1->userid);
2844          $this->assertEquals($m1id, $mua1->messageid);
2845          $this->assertEquals(api::MESSAGE_ACTION_DELETED, $mua1->action);
2846  
2847          $this->assertEquals($user1->id, $mua2->userid);
2848          $this->assertEquals($m2id, $mua2->messageid);
2849          $this->assertEquals(api::MESSAGE_ACTION_DELETED, $mua2->action);
2850  
2851          $this->assertEquals($user1->id, $mua3->userid);
2852          $this->assertEquals($m3id, $mua3->messageid);
2853          $this->assertEquals(api::MESSAGE_ACTION_DELETED, $mua3->action);
2854  
2855          $this->assertEquals($user1->id, $mua4->userid);
2856          $this->assertEquals($m4id, $mua4->messageid);
2857          $this->assertEquals(api::MESSAGE_ACTION_DELETED, $mua4->action);
2858  
2859          // Delete the self-conversation as user 1.
2860          api::delete_conversation_by_id($user1->id, $sc1->id);
2861  
2862          $muas = $DB->get_records('message_user_actions', array(), 'timecreated ASC');
2863          $this->assertCount(5, $muas);
2864  
2865          // Sort by id.
2866          ksort($muas);
2867  
2868          $mua1 = array_shift($muas);
2869          $mua2 = array_shift($muas);
2870          $mua3 = array_shift($muas);
2871          $mua4 = array_shift($muas);
2872          $mua5 = array_shift($muas);
2873  
2874          // Check only messages in self-conversion for user1 are deleted (self-conversation for user2 shouldn't be removed).
2875          $this->assertEquals($user1->id, $mua5->userid);
2876          $this->assertEquals($m5id, $mua5->messageid);
2877          $this->assertEquals(api::MESSAGE_ACTION_DELETED, $mua5->action);
2878      }
2879  
2880      /**
2881       * Tests counting unread conversations.
2882       */
2883      public function test_count_unread_conversations() {
2884          $this->resetAfterTest(true);
2885  
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();
2891  
2892          // The person wanting the conversation count.
2893          $this->setUser($user1);
2894  
2895          // Send some messages back and forth, have some different conversations with different users.
2896          $this->send_fake_message($user1, $user2, 'Yo!');
2897          $this->send_fake_message($user2, $user1, 'Sup mang?');
2898          $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!');
2899          $this->send_fake_message($user2, $user1, 'Word.');
2900  
2901          $this->send_fake_message($user1, $user3, 'Booyah');
2902          $this->send_fake_message($user3, $user1, 'Whaaat?');
2903          $this->send_fake_message($user1, $user3, 'Nothing.');
2904          $this->send_fake_message($user3, $user1, 'Cool.');
2905  
2906          $this->send_fake_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?');
2907          $this->send_fake_message($user4, $user1, 'Yah brah, it\'s pretty rad.');
2908          $this->send_fake_message($user1, $user4, 'Dope.');
2909  
2910          // Check the amount for the current user.
2911          $this->assertEquals(3, api::count_unread_conversations());
2912  
2913          // Check the amount for the second user.
2914          $this->assertEquals(1, api::count_unread_conversations($user2));
2915      }
2916  
2917      /**
2918       * Tests counting unread conversations where one conversation is disabled.
2919       */
2920      public function test_count_unread_conversations_disabled() {
2921          $this->resetAfterTest(true);
2922  
2923          // Create some users.
2924          $user1 = self::getDataGenerator()->create_user();
2925          $user2 = self::getDataGenerator()->create_user();
2926          $user3 = self::getDataGenerator()->create_user();
2927          $user4 = self::getDataGenerator()->create_user();
2928  
2929          // The person wanting the conversation count.
2930          $this->setUser($user1);
2931  
2932          // Send some messages back and forth, have some different conversations with different users.
2933          $this->send_fake_message($user1, $user2, 'Yo!');
2934          $this->send_fake_message($user2, $user1, 'Sup mang?');
2935          $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!');
2936          $this->send_fake_message($user2, $user1, 'Word.');
2937  
2938          $this->send_fake_message($user1, $user3, 'Booyah');
2939          $this->send_fake_message($user3, $user1, 'Whaaat?');
2940          $this->send_fake_message($user1, $user3, 'Nothing.');
2941          $this->send_fake_message($user3, $user1, 'Cool.');
2942  
2943          $this->send_fake_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?');
2944          $this->send_fake_message($user4, $user1, 'Yah brah, it\'s pretty rad.');
2945          $this->send_fake_message($user1, $user4, 'Dope.');
2946  
2947          // Let's disable the last conversation.
2948          $conversationid = api::get_conversation_between_users([$user1->id, $user4->id]);
2949          api::disable_conversation($conversationid);
2950  
2951          // Check that the disabled conversation was not included.
2952          $this->assertEquals(2, api::count_unread_conversations());
2953      }
2954  
2955      /**
2956       * Tests deleting a conversation.
2957       */
2958      public function test_get_all_message_preferences() {
2959          $user = self::getDataGenerator()->create_user();
2960          $this->setUser($user);
2961  
2962          // Set a couple of preferences to test.
2963          set_user_preference('message_provider_mod_assign_assign_notification_loggedin', 'popup', $user);
2964          set_user_preference('message_provider_mod_assign_assign_notification_loggedoff', 'email', $user);
2965  
2966          $processors = get_message_processors();
2967          $providers = message_get_providers_for_user($user->id);
2968          $prefs = api::get_all_message_preferences($processors, $providers, $user);
2969  
2970          $this->assertEquals(1, $prefs->mod_assign_assign_notification_loggedin['popup']);
2971          $this->assertEquals(1, $prefs->mod_assign_assign_notification_loggedoff['email']);
2972      }
2973  
2974      /**
2975       * Tests the user can send a message.
2976       */
2977      public function test_can_send_message() {
2978          // Create some users.
2979          $user1 = self::getDataGenerator()->create_user();
2980          $user2 = self::getDataGenerator()->create_user();
2981  
2982          // Set as the first user.
2983          $this->setUser($user1);
2984  
2985          // With the default privacy setting, users can't message them.
2986          $this->assertFalse(api::can_send_message($user2->id, $user1->id));
2987  
2988          // Enrol users to the same course.
2989          $course = $this->getDataGenerator()->create_course();
2990          $this->getDataGenerator()->enrol_user($user1->id, $course->id);
2991          $this->getDataGenerator()->enrol_user($user2->id, $course->id);
2992          // After enrolling users to the course, they should be able to message them with the default privacy setting.
2993          $this->assertTrue(api::can_send_message($user2->id, $user1->id));
2994      }
2995  
2996      /**
2997       * Tests the user can't send a message without proper capability.
2998       */
2999      public function test_can_send_message_without_sendmessage_cap() {
3000          global $DB;
3001  
3002          // Create some users.
3003          $user1 = self::getDataGenerator()->create_user();
3004          $user2 = self::getDataGenerator()->create_user();
3005  
3006          // Set as the user 1.
3007          $this->setUser($user1);
3008  
3009          // Remove the capability to send a message.
3010          $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
3011          unassign_capability('moodle/site:sendmessage', $roleids['user'],
3012              \context_system::instance());
3013  
3014          // Check that we can not post a message without the capability.
3015          $this->assertFalse(api::can_send_message($user2->id, $user1->id));
3016      }
3017  
3018      /**
3019       * Tests the user can send a message when they are contact.
3020       */
3021      public function test_can_send_message_when_contact() {
3022          // Create some users.
3023          $user1 = self::getDataGenerator()->create_user();
3024          $user2 = self::getDataGenerator()->create_user();
3025  
3026          // Set as the first user.
3027          $this->setUser($user1);
3028  
3029          // Check that we can not send user2 a message.
3030          $this->assertFalse(api::can_send_message($user2->id, $user1->id));
3031  
3032          // Add users as contacts.
3033          api::add_contact($user1->id, $user2->id);
3034  
3035          // Check that the return result is now true.
3036          $this->assertTrue(api::can_send_message($user2->id, $user1->id));
3037      }
3038  
3039      /**
3040       * Tests the user can't send a message if they are not a contact and the user
3041       * has requested messages only from contacts.
3042       */
3043      public function test_can_send_message_when_not_contact() {
3044          // Create some users.
3045          $user1 = self::getDataGenerator()->create_user();
3046          $user2 = self::getDataGenerator()->create_user();
3047  
3048          // Set as the first user.
3049          $this->setUser($user1);
3050  
3051          // Set the second user's preference to not receive messages from non-contacts.
3052          set_user_preference('message_blocknoncontacts', api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2->id);
3053  
3054          // Check that we can not send user 2 a message.
3055          $this->assertFalse(api::can_send_message($user2->id, $user1->id));
3056      }
3057  
3058      /**
3059       * Tests the user can't send a message if they are blocked.
3060       */
3061      public function test_can_send_message_when_blocked() {
3062          // Create some users.
3063          $user1 = self::getDataGenerator()->create_user();
3064          $user2 = self::getDataGenerator()->create_user();
3065  
3066          // Set the user.
3067          $this->setUser($user1);
3068  
3069          // Block the second user.
3070          api::block_user($user1->id, $user2->id);
3071  
3072          // Check that the second user can no longer send the first user a message.
3073          $this->assertFalse(api::can_send_message($user1->id, $user2->id));
3074      }
3075  
3076      /**
3077       * Tests the user can send a message when site-wide messaging setting is enabled,
3078       * even if they are not a contact and are not members of the same course.
3079       */
3080      public function test_can_send_message_site_messaging_setting() {
3081          // Create some users.
3082          $user1 = self::getDataGenerator()->create_user();
3083          $user2 = self::getDataGenerator()->create_user();
3084  
3085          // Set as the first user.
3086          $this->setUser($user1);
3087  
3088          // By default, user only can be messaged by contacts and members of any of his/her courses.
3089          $this->assertFalse(api::can_send_message($user2->id, $user1->id));
3090  
3091          // Enable site-wide messagging privacy setting. The user will be able to receive messages from everybody.
3092          set_config('messagingallusers', true);
3093  
3094          // Set the second user's preference to receive messages from everybody.
3095          set_user_preference('message_blocknoncontacts', api::MESSAGE_PRIVACY_SITE, $user2->id);
3096  
3097          // Check that we can send user2 a message.
3098          $this->assertTrue(api::can_send_message($user2->id, $user1->id));
3099  
3100          // Disable site-wide messagging privacy setting. The user will be able to receive messages from contacts
3101          // and members sharing a course with her.
3102          set_config('messagingallusers', false);
3103  
3104          // As site-wide messaging setting is disabled, the value for user2 will be changed to MESSAGE_PRIVACY_COURSEMEMBER.
3105          $this->assertFalse(api::can_send_message($user2->id, $user1->id));
3106  
3107          // Enrol users to the same course.
3108          $course = $this->getDataGenerator()->create_course();
3109          $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3110          $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3111          // Check that we can send user2 a message because they are sharing a course.
3112          $this->assertTrue(api::can_send_message($user2->id, $user1->id));
3113  
3114          // Set the second user's preference to receive messages only from contacts.
3115          set_user_preference('message_blocknoncontacts', api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2->id);
3116          // Check that now the user2 can't be contacted because user1 is not their contact.
3117          $this->assertFalse(api::can_send_message($user2->id, $user1->id));
3118  
3119          // Make contacts user1 and user2.
3120          api::add_contact($user2->id, $user1->id);
3121          // Check that we can send user2 a message because they are contacts.
3122          $this->assertTrue(api::can_send_message($user2->id, $user1->id));
3123      }
3124  
3125      /**
3126       * Tests the user with the messageanyuser capability can send a message.
3127       */
3128      public function test_can_send_message_with_messageanyuser_cap() {
3129          global $DB;
3130  
3131          // Create some users.
3132          $teacher1 = self::getDataGenerator()->create_user();
3133          $student1 = self::getDataGenerator()->create_user();
3134          $student2 = self::getDataGenerator()->create_user();
3135  
3136          // Create users not enrolled in any course.
3137          $user1 = self::getDataGenerator()->create_user();
3138  
3139          // Create a course.
3140          $course1 = $this->getDataGenerator()->create_course();
3141  
3142          // Enrol the users in the course.
3143          $this->getDataGenerator()->enrol_user($teacher1->id, $course1->id, 'editingteacher');
3144          $this->getDataGenerator()->enrol_user($student1->id, $course1->id, 'student');
3145          $this->getDataGenerator()->enrol_user($student2->id, $course1->id, 'student');
3146  
3147          // Set some student preferences to not receive messages from non-contacts.
3148          set_user_preference('message_blocknoncontacts', api::MESSAGE_PRIVACY_ONLYCONTACTS, $student1->id);
3149  
3150          // Check that we can send student1 a message because teacher has the messageanyuser cap by default.
3151          $this->assertTrue(api::can_send_message($student1->id, $teacher1->id));
3152  
3153          // Check that the teacher can't contact user1 because it's not his teacher.
3154          $this->assertFalse(api::can_send_message($user1->id, $teacher1->id));
3155  
3156          // Remove the messageanyuser capability from the course1 for teachers.
3157          $coursecontext = \context_course::instance($course1->id);
3158          $teacherrole = $DB->get_record('role', ['shortname' => 'editingteacher']);
3159          assign_capability('moodle/site:messageanyuser', CAP_PROHIBIT, $teacherrole->id, $coursecontext->id);
3160          $coursecontext->mark_dirty();
3161  
3162          // Check that we can't send user1 a message because they are not contacts.
3163          $this->assertFalse(api::can_send_message($student1->id, $teacher1->id));
3164  
3165          // However, teacher can message student2 because they are sharing a course.
3166          $this->assertTrue(api::can_send_message($student2->id, $teacher1->id));
3167      }
3168  
3169      /**
3170       * Tests the user when blocked will not be able to send messages if they are blocked.
3171       */
3172      public function test_can_send_message_even_if_blocked() {
3173          $this->resetAfterTest();
3174  
3175          $user1 = self::getDataGenerator()->create_user();
3176          $user2 = self::getDataGenerator()->create_user();
3177  
3178          $this->assertFalse(api::can_send_message($user2->id, $user1->id, true));
3179      }
3180  
3181      /**
3182       * Tests the user will be able to send a message even if they are blocked as the user
3183       * has the capability 'moodle/site:messageanyuser'.
3184       */
3185      public function test_can_send_message_even_if_blocked_with_message_any_user_cap() {
3186          global $DB;
3187  
3188          $this->resetAfterTest();
3189  
3190          $user1 = self::getDataGenerator()->create_user();
3191          $user2 = self::getDataGenerator()->create_user();
3192  
3193          $authenticateduserrole = $DB->get_record('role', array('shortname' => 'user'));
3194          assign_capability('moodle/site:messageanyuser', CAP_ALLOW, $authenticateduserrole->id, \context_system::instance(), true);
3195  
3196          $this->assertTrue(api::can_send_message($user2->id, $user1->id, true));
3197      }
3198  
3199      /**
3200       * Tests the user will be able to send a message even if they are blocked as the user
3201       * has the capability 'moodle/site:readallmessages'.
3202       */
3203      public function test_can_send_message_even_if_blocked_with_read_all_message_cap() {
3204          global $DB;
3205  
3206          $this->resetAfterTest();
3207  
3208          $user1 = self::getDataGenerator()->create_user();
3209          $user2 = self::getDataGenerator()->create_user();
3210  
3211          $authenticateduserrole = $DB->get_record('role', array('shortname' => 'user'));
3212          assign_capability('moodle/site:readallmessages', CAP_ALLOW, $authenticateduserrole->id, \context_system::instance(), true);
3213  
3214          $this->assertTrue(api::can_send_message($user2->id, $user1->id, true));
3215      }
3216  
3217      /**
3218       * Tests the user can not always send a message if they are blocked just because they share a course.
3219       */
3220      public function test_can_send_message_even_if_blocked_shared_course() {
3221          $this->resetAfterTest();
3222  
3223          // Create some users.
3224          $user1 = self::getDataGenerator()->create_user();
3225          $user2 = self::getDataGenerator()->create_user();
3226  
3227          $course = self::getDataGenerator()->create_course();
3228  
3229          $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3230          $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3231  
3232          $this->assertFalse(api::can_send_message($user2->id, $user1->id, true));
3233      }
3234  
3235      /**
3236       * Tests the user can always send a message even if they are blocked because they share a course and
3237       * have the capability 'moodle/site:messageanyuser' at the course context.
3238       */
3239      public function test_can_send_message_even_if_blocked_shared_course_with_message_any_user_cap() {
3240          global $DB;
3241  
3242          $this->resetAfterTest();
3243  
3244          $editingteacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
3245  
3246          $teacher = self::getDataGenerator()->create_user();
3247          $student = self::getDataGenerator()->create_user();
3248  
3249          $course = self::getDataGenerator()->create_course();
3250  
3251          $this->getDataGenerator()->enrol_user($teacher->id, $course->id, $editingteacherrole->id);
3252          $this->getDataGenerator()->enrol_user($student->id, $course->id);
3253  
3254          assign_capability('moodle/site:messageanyuser', CAP_ALLOW, $editingteacherrole->id,
3255              \context_course::instance($course->id), true);
3256  
3257          // Check that the second user can no longer send the first user a message.
3258          $this->assertTrue(api::can_send_message($student->id, $teacher->id, true));
3259      }
3260  
3261      /**
3262       * Test that calling to can_post_message() now shows debugging. MDL-65093.
3263       *
3264       * @deprecated since 3.8
3265       * @todo Final deprecation in MDL-66266
3266       */
3267      public function test_can_post_emits_debugging() {
3268          // Create some users.
3269          $user1 = self::getDataGenerator()->create_user();
3270          $user2 = self::getDataGenerator()->create_user();
3271  
3272          // Set as the first user.
3273          $this->setUser($user1);
3274  
3275          // With the default privacy setting, users can't message them.
3276          $this->assertFalse(\core_message\api::can_post_message($user2));
3277          $this->assertDebuggingCalled('\core_message\api::can_post_message is deprecated, please use ' .
3278              '\core_message\api::can_send_message instead.', DEBUG_DEVELOPER);
3279      }
3280  
3281      /**
3282       * Verify the expected behaviour of the can_send_message_to_conversation() method for authenticated users with default settings.
3283       */
3284      public function test_can_send_message_to_conversation_basic() {
3285          // Create some users.
3286          $user1 = self::getDataGenerator()->create_user();
3287          $user2 = self::getDataGenerator()->create_user();
3288          $user3 = self::getDataGenerator()->create_user();
3289  
3290          // Create an individual conversation between user1 and user2.
3291          $ic1 = api::create_conversation(
3292              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3293              [
3294                  $user1->id,
3295                  $user2->id
3296              ]
3297          );
3298  
3299          // Create a group conversation between and users 1, 2 and 3.
3300          $gc1 = api::create_conversation(
3301              api::MESSAGE_CONVERSATION_TYPE_GROUP,
3302              [
3303                  $user1->id,
3304                  $user2->id,
3305                  $user3->id
3306              ]
3307          );
3308  
3309          // Get a self-conversation for user1.
3310          $sc1 = api::get_self_conversation($user1->id);
3311  
3312          // For group conversations, there are no user privacy checks, so only membership in the conversation is needed.
3313          $this->assertTrue(api::can_send_message_to_conversation($user1->id, $gc1->id));
3314  
3315          // For self conversations, there are no user privacy checks, so only membership in the conversation is needed.
3316          $this->assertTrue(api::can_send_message_to_conversation($user1->id, $sc1->id));
3317  
3318          // For individual conversations, the default privacy setting of 'only contacts and course members' applies.
3319          // Users are not in the same course, nor are they contacts, so messages cannot be sent.
3320          $this->assertFalse(api::can_send_message_to_conversation($user1->id, $ic1->id));
3321  
3322          // Enrol the users into the same course.
3323          $course = $this->getDataGenerator()->create_course();
3324          $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3325          $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3326  
3327          // After enrolling users to the course, they should be able to message them with the default privacy setting.
3328          $this->assertTrue(api::can_send_message_to_conversation($user1->id, $ic1->id));
3329      }
3330  
3331      /**
3332       * Verify the behaviour of can_send_message_to_conversation() for authenticated users without the sendmessage capability.
3333       */
3334      public function test_can_send_message_to_conversation_sendmessage_cap() {
3335          global $DB;
3336  
3337          $user1 = self::getDataGenerator()->create_user();
3338          $user2 = self::getDataGenerator()->create_user();
3339          $user3 = self::getDataGenerator()->create_user();
3340  
3341          // Enrol the users into the same course.
3342          $course = $this->getDataGenerator()->create_course();
3343          $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3344          $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3345          $this->getDataGenerator()->enrol_user($user3->id, $course->id);
3346  
3347          // Create an individual conversation between user1 and user2.
3348          $ic1 = api::create_conversation(
3349              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3350              [
3351                  $user1->id,
3352                  $user2->id
3353              ]
3354          );
3355  
3356          // Group conversation between and users 1, 2 and 3.
3357          $gc1 = api::create_conversation(
3358              api::MESSAGE_CONVERSATION_TYPE_GROUP,
3359              [
3360                  $user1->id,
3361                  $user2->id,
3362                  $user3->id
3363              ]
3364          );
3365  
3366          // Default settings - user1 can send a message to both conversations.
3367          $this->assertTrue(api::can_send_message_to_conversation($user1->id, $ic1->id));
3368          $this->assertTrue(api::can_send_message_to_conversation($user1->id, $gc1->id));
3369  
3370          // Remove the capability to send a message.
3371          $roleids = $DB->get_records_menu('role', null, '', 'shortname, id');
3372          unassign_capability('moodle/site:sendmessage', $roleids['user'], \context_system::instance());
3373  
3374          // Verify that a user cannot send a message to either an individual or a group conversation.
3375          $this->assertFalse(api::can_send_message_to_conversation($user1->id, $ic1->id));
3376          $this->assertFalse(api::can_send_message_to_conversation($user1->id, $gc1->id));
3377      }
3378  
3379      /**
3380       * Verify the behaviour of can_send_message_to_conversation() for authenticated users without the messageanyuser capability.
3381       */
3382      public function test_can_send_message_to_conversation_messageanyuser_cap() {
3383          global $DB;
3384  
3385          $user1 = self::getDataGenerator()->create_user();
3386          $user2 = self::getDataGenerator()->create_user();
3387          $user3 = self::getDataGenerator()->create_user();
3388  
3389          // Enrol the users into the same course.
3390          $course = $this->getDataGenerator()->create_course();
3391          $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3392          $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3393          $this->getDataGenerator()->enrol_user($user3->id, $course->id);
3394  
3395          // Create an individual conversation between user1 and user2.
3396          $ic1 = api::create_conversation(
3397              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3398              [
3399                  $user1->id,
3400                  $user2->id
3401              ]
3402          );
3403  
3404          // Group conversation between and users 1, 2 and 3.
3405          $gc1 = api::create_conversation(
3406              api::MESSAGE_CONVERSATION_TYPE_GROUP,
3407              [
3408                  $user1->id,
3409                  $user2->id,
3410                  $user3->id
3411              ]
3412          );
3413  
3414          // Update the message preference for user2, so they can only be messaged by contacts.
3415          set_user_preference('message_blocknoncontacts', api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2->id);
3416  
3417          // Verify that the user cannot be contacted in the individual conversation and that groups are unaffected.
3418          $this->assertFalse(api::can_send_message_to_conversation($user1->id, $ic1->id));
3419          $this->assertTrue(api::can_send_message_to_conversation($user1->id, $gc1->id));
3420  
3421          // Assign the 'messageanyuser' capability to user1 at system context.
3422          $systemcontext = \context_system::instance();
3423          $authenticateduser = $DB->get_record('role', ['shortname' => 'user']);
3424          assign_capability('moodle/site:messageanyuser', CAP_ALLOW, $authenticateduser->id, $systemcontext->id);
3425  
3426          // Check that user1 can now message user2 due to the capability, and that group conversations is again unaffected.
3427          $this->assertTrue(api::can_send_message_to_conversation($user1->id, $ic1->id));
3428          $this->assertTrue(api::can_send_message_to_conversation($user1->id, $gc1->id));
3429      }
3430  
3431      /**
3432       * Test verifying that users cannot send messages to conversations they are not a part of.
3433       */
3434      public function test_can_send_message_to_conversation_non_member() {
3435          // Create some users.
3436          $user1 = self::getDataGenerator()->create_user();
3437          $user2 = self::getDataGenerator()->create_user();
3438          $user3 = self::getDataGenerator()->create_user();
3439          $user4 = self::getDataGenerator()->create_user();
3440  
3441          // Enrol the users into the same course.
3442          $course = $this->getDataGenerator()->create_course();
3443          $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3444          $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3445          $this->getDataGenerator()->enrol_user($user3->id, $course->id);
3446          $this->getDataGenerator()->enrol_user($user4->id, $course->id);
3447  
3448          // Create an individual conversation between user1 and user2.
3449          $ic1 = api::create_conversation(
3450              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3451              [
3452                  $user1->id,
3453                  $user2->id
3454              ]
3455          );
3456  
3457          // Create a group conversation between and users 1, 2 and 3.
3458          $gc1 = api::create_conversation(
3459              api::MESSAGE_CONVERSATION_TYPE_GROUP,
3460              [
3461                  $user1->id,
3462                  $user2->id,
3463                  $user3->id
3464              ]
3465          );
3466  
3467          // Get a self-conversation for user1.
3468          $sc1 = api::get_self_conversation($user1->id);
3469  
3470          // Verify, non members cannot send a message.
3471          $this->assertFalse(api::can_send_message_to_conversation($user4->id, $gc1->id));
3472          $this->assertFalse(api::can_send_message_to_conversation($user4->id, $ic1->id));
3473          $this->assertFalse(api::can_send_message_to_conversation($user4->id, $sc1->id));
3474      }
3475  
3476      /**
3477       * Test verifying the behaviour of the can_send_message_to_conversation method when privacy is set to contacts only.
3478       */
3479      public function test_can_send_message_to_conversation_privacy_contacts_only() {
3480          // Create some users.
3481          $user1 = self::getDataGenerator()->create_user();
3482          $user2 = self::getDataGenerator()->create_user();
3483          $user3 = self::getDataGenerator()->create_user();
3484  
3485          // Create an individual conversation between user1 and user2.
3486          $ic1 = api::create_conversation(
3487              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3488              [
3489                  $user1->id,
3490                  $user2->id
3491              ]
3492          );
3493  
3494          // Create a group conversation between and users 1, 2 and 3.
3495          $gc1 = api::create_conversation(
3496              api::MESSAGE_CONVERSATION_TYPE_GROUP,
3497              [
3498                  $user1->id,
3499                  $user2->id,
3500                  $user3->id
3501              ]
3502          );
3503  
3504          // Set the message privacy preference to 'contacts only' for user 2.
3505          set_user_preference('message_blocknoncontacts', api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2->id);
3506  
3507          // Verify that user1 cannot send a message to the individual conversation, but that the group conversation is unaffected.
3508          $this->assertFalse(api::can_send_message_to_conversation($user1->id, $ic1->id));
3509          $this->assertTrue(api::can_send_message_to_conversation($user1->id, $gc1->id));
3510  
3511          // Now, simulate a contact request (and approval) between user1 and user2.
3512          api::create_contact_request($user1->id, $user2->id);
3513          api::confirm_contact_request($user1->id, $user2->id);
3514  
3515          // Verify user1 can now message user2 again via their individual conversation.
3516          $this->assertTrue(api::can_send_message_to_conversation($user1->id, $ic1->id));
3517      }
3518  
3519      /**
3520       * Test verifying the behaviour of the can_send_message_to_conversation method when privacy is set to contacts / course members.
3521       */
3522      public function test_can_send_message_to_conversation_privacy_contacts_course() {
3523          // Create some users.
3524          $user1 = self::getDataGenerator()->create_user();
3525          $user2 = self::getDataGenerator()->create_user();
3526          $user3 = self::getDataGenerator()->create_user();
3527  
3528          // Set the message privacy preference to 'contacts + course members' for user 2.
3529          set_user_preference('message_blocknoncontacts', api::MESSAGE_PRIVACY_COURSEMEMBER, $user2->id);
3530  
3531          // Create an individual conversation between user1 and user2.
3532          $ic1 = api::create_conversation(
3533              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3534              [
3535                  $user1->id,
3536                  $user2->id
3537              ]
3538          );
3539  
3540          // Create a group conversation between and users 1, 2 and 3.
3541          $gc1 = api::create_conversation(
3542              api::MESSAGE_CONVERSATION_TYPE_GROUP,
3543              [
3544                  $user1->id,
3545                  $user2->id,
3546                  $user3->id
3547              ]
3548          );
3549  
3550          // Verify that users in a group conversation can message one another (i.e. privacy controls ignored).
3551          $this->assertTrue(api::can_send_message_to_conversation($user1->id, $gc1->id));
3552  
3553          // Verify that user1 can not message user2 unless they are either contacts, or share a course.
3554          $this->assertFalse(api::can_send_message_to_conversation($user1->id, $ic1->id));
3555  
3556          // Enrol the users into the same course.
3557          $course = $this->getDataGenerator()->create_course();
3558          $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3559          $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3560          $this->getDataGenerator()->enrol_user($user3->id, $course->id);
3561  
3562          // Verify that user1 can send a message to user2, based on the shared course, without being a contact.
3563          $this->assertFalse(api::is_contact($user1->id, $user2->id));
3564          $this->assertTrue(api::can_send_message_to_conversation($user1->id, $ic1->id));
3565      }
3566  
3567      /**
3568       * Test verifying the behaviour of the can_send_message_to_conversation method when privacy is set to any user.
3569       */
3570      public function test_can_send_message_to_conversation_privacy_sitewide() {
3571          // Create some users.
3572          $user1 = self::getDataGenerator()->create_user();
3573          $user2 = self::getDataGenerator()->create_user();
3574          $user3 = self::getDataGenerator()->create_user();
3575  
3576          // Create an individual conversation between user1 and user2.
3577          $ic1 = api::create_conversation(
3578              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3579              [
3580                  $user1->id,
3581                  $user2->id
3582              ]
3583          );
3584  
3585          // Create a group conversation between and users 1, 2 and 3.
3586          $gc1 = api::create_conversation(
3587              api::MESSAGE_CONVERSATION_TYPE_GROUP,
3588              [
3589                  $user1->id,
3590                  $user2->id,
3591                  $user3->id
3592              ]
3593          );
3594  
3595          // By default, the messaging privacy dictates that users can only be contacted by contacts, and members of their courses.
3596          // Verify also, that groups are not restricted in this way.
3597          $this->assertFalse(api::can_send_message_to_conversation($user1->id, $ic1->id));
3598          $this->assertTrue(api::can_send_message_to_conversation($user1->id, $gc1->id));
3599  
3600          // Enable site-wide messagging privacy setting.
3601          // This enables a privacy option for users, allowing them to choose to be contactable by anybody on the site.
3602          set_config('messagingallusers', true);
3603  
3604          // Set the second user's preference to receive messages from everybody.
3605          set_user_preference('message_blocknoncontacts', api::MESSAGE_PRIVACY_SITE, $user2->id);
3606  
3607          // Check that user1 can send user2 a message, and that the group conversation is unaffected.
3608          $this->assertTrue(api::can_send_message_to_conversation($user1->id, $ic1->id));
3609          $this->assertTrue(api::can_send_message_to_conversation($user1->id, $gc1->id));
3610  
3611          // Disable site-wide messagging privacy setting. The user will be able to receive messages from contacts
3612          // and members sharing a course with her.
3613          set_config('messagingallusers', false);
3614  
3615          // As site-wide messaging setting is disabled, the value for user2 will be changed to MESSAGE_PRIVACY_COURSEMEMBER.
3616          // Verify also that the group conversation is unaffected.
3617          $this->assertFalse(api::can_send_message_to_conversation($user1->id, $ic1->id));
3618          $this->assertTrue(api::can_send_message_to_conversation($user1->id, $gc1->id));
3619      }
3620  
3621      /**
3622       * Test verifying the behaviour of the can_send_message_to_conversation method when a user is blocked.
3623       */
3624      public function test_can_send_message_to_conversation_when_blocked() {
3625          $user1 = self::getDataGenerator()->create_user();
3626          $user2 = self::getDataGenerator()->create_user();
3627          $user3 = self::getDataGenerator()->create_user();
3628  
3629          // Create an individual conversation between user1 and user2.
3630          $ic1 = api::create_conversation(
3631              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
3632              [
3633                  $user1->id,
3634                  $user2->id
3635              ]
3636          );
3637  
3638          // Create a group conversation between and users 1, 2 and 3.
3639          $gc1 = api::create_conversation(
3640              api::MESSAGE_CONVERSATION_TYPE_GROUP,
3641              [
3642                  $user1->id,
3643                  $user2->id,
3644                  $user3->id
3645              ]
3646          );
3647  
3648          // Enrol the users into the same course.
3649          $course = $this->getDataGenerator()->create_course();
3650          $this->getDataGenerator()->enrol_user($user1->id, $course->id);
3651          $this->getDataGenerator()->enrol_user($user2->id, $course->id);
3652          $this->getDataGenerator()->enrol_user($user3->id, $course->id);
3653  
3654          // Block the second user.
3655          api::block_user($user1->id, $user2->id);
3656  
3657          // Check that user2 can not send user1 a message in their individual conversation.
3658          $this->assertFalse(api::can_send_message_to_conversation($user2->id, $ic1->id));
3659  
3660          // Verify that group conversations are unaffected.
3661          $this->assertTrue(api::can_send_message_to_conversation($user1->id, $gc1->id));
3662          $this->assertTrue(api::can_send_message_to_conversation($user2->id, $gc1->id));
3663      }
3664  
3665      /**
3666       * Tests get_user_privacy_messaging_preference method.
3667       */
3668      public function test_get_user_privacy_messaging_preference() {
3669          // Create some users.
3670          $user1 = self::getDataGenerator()->create_user();
3671          $user2 = self::getDataGenerator()->create_user();
3672          $user3 = self::getDataGenerator()->create_user();
3673  
3674          // Enable site-wide messagging privacy setting. The user will be able to receive messages from everybody.
3675          set_config('messagingallusers', true);
3676  
3677          // Set some user preferences.
3678          set_user_preference('message_blocknoncontacts', api::MESSAGE_PRIVACY_SITE, $user1->id);
3679          set_user_preference('message_blocknoncontacts', api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2->id);
3680  
3681          // Check the returned value for each user.
3682          $this->assertEquals(
3683              api::MESSAGE_PRIVACY_SITE,
3684              api::get_user_privacy_messaging_preference($user1->id)
3685          );
3686          $this->assertEquals(
3687              api::MESSAGE_PRIVACY_ONLYCONTACTS,
3688              api::get_user_privacy_messaging_preference($user2->id)
3689          );
3690          $this->assertEquals(
3691              api::MESSAGE_PRIVACY_SITE,
3692              api::get_user_privacy_messaging_preference($user3->id)
3693          );
3694  
3695          // Disable site-wide messagging privacy setting. The user will be able to receive messages from members of their course.
3696          set_config('messagingallusers', false);
3697  
3698          // Check the returned value for each user.
3699          $this->assertEquals(
3700              api::MESSAGE_PRIVACY_COURSEMEMBER,
3701              api::get_user_privacy_messaging_preference($user1->id)
3702          );
3703          $this->assertEquals(
3704              api::MESSAGE_PRIVACY_ONLYCONTACTS,
3705              api::get_user_privacy_messaging_preference($user2->id)
3706          );
3707          $this->assertEquals(
3708              api::MESSAGE_PRIVACY_COURSEMEMBER,
3709              api::get_user_privacy_messaging_preference($user3->id)
3710          );
3711      }
3712  
3713      /*
3714       * Tes get_message_processor api.
3715       */
3716      public function test_get_message_processor() {
3717          $processors = get_message_processors(true);
3718          if (empty($processors)) {
3719              $this->markTestSkipped("No message processors found");
3720          }
3721  
3722          $name = key($processors);
3723          $processor = current($processors);
3724          $testprocessor = api::get_message_processor($name);
3725          $this->assertEquals($processor->name, $testprocessor->name);
3726          $this->assertEquals($processor->enabled, $testprocessor->enabled);
3727          $this->assertEquals($processor->available, $testprocessor->available);
3728          $this->assertEquals($processor->configured, $testprocessor->configured);
3729  
3730          // Disable processor and test.
3731          api::update_processor_status($testprocessor, 0);
3732          $testprocessor = api::get_message_processor($name, true);
3733          $this->assertEmpty($testprocessor);
3734          $testprocessor = api::get_message_processor($name);
3735          $this->assertEquals($processor->name, $testprocessor->name);
3736          $this->assertEquals(0, $testprocessor->enabled);
3737  
3738          // Enable again and test.
3739          api::update_processor_status($testprocessor, 1);
3740          $testprocessor = api::get_message_processor($name, true);
3741          $this->assertEquals($processor->name, $testprocessor->name);
3742          $this->assertEquals(1, $testprocessor->enabled);
3743          $testprocessor = api::get_message_processor($name);
3744          $this->assertEquals($processor->name, $testprocessor->name);
3745          $this->assertEquals(1, $testprocessor->enabled);
3746      }
3747  
3748      /**
3749       * Test method update_processor_status.
3750       */
3751      public function test_update_processor_status() {
3752          $processors = get_message_processors();
3753          if (empty($processors)) {
3754              $this->markTestSkipped("No message processors found");
3755          }
3756          $name = key($processors);
3757          $testprocessor = current($processors);
3758  
3759          // Enable.
3760          api::update_processor_status($testprocessor, 1);
3761          $testprocessor = api::get_message_processor($name);
3762          $this->assertEquals(1, $testprocessor->enabled);
3763  
3764          // Disable.
3765          api::update_processor_status($testprocessor, 0);
3766          $testprocessor = api::get_message_processor($name);
3767          $this->assertEquals(0, $testprocessor->enabled);
3768  
3769          // Enable again.
3770          api::update_processor_status($testprocessor, 1);
3771          $testprocessor = api::get_message_processor($name);
3772          $this->assertEquals(1, $testprocessor->enabled);
3773      }
3774  
3775      /**
3776       * Test method is_user_enabled.
3777       */
3778      public function is_user_enabled() {
3779          $processors = get_message_processors();
3780          if (empty($processors)) {
3781              $this->markTestSkipped("No message processors found");
3782          }
3783          $name = key($processors);
3784          $testprocessor = current($processors);
3785  
3786          // Enable.
3787          api::update_processor_status($testprocessor, 1);
3788          $status = api::is_processor_enabled($name);
3789          $this->assertEquals(1, $status);
3790  
3791          // Disable.
3792          api::update_processor_status($testprocessor, 0);
3793          $status = api::is_processor_enabled($name);
3794          $this->assertEquals(0, $status);
3795  
3796          // Enable again.
3797          api::update_processor_status($testprocessor, 1);
3798          $status = api::is_processor_enabled($name);
3799          $this->assertEquals(1, $status);
3800      }
3801  
3802      /**
3803       * Test returning blocked users.
3804       */
3805      public function test_get_blocked_users() {
3806          global $USER;
3807  
3808          // Set this user as the admin.
3809          $this->setAdminUser();
3810  
3811          // Create a user to add to the admin's contact list.
3812          $user1 = $this->getDataGenerator()->create_user();
3813          $user2 = $this->getDataGenerator()->create_user();
3814  
3815          // Add users to the admin's contact list.
3816          api::block_user($USER->id, $user2->id);
3817  
3818          $this->assertCount(1, api::get_blocked_users($USER->id));
3819  
3820          // Block other user.
3821          api::block_user($USER->id, $user1->id);
3822          $this->assertCount(2, api::get_blocked_users($USER->id));
3823  
3824          // Test deleting users.
3825          delete_user($user1);
3826          $this->assertCount(1, api::get_blocked_users($USER->id));
3827      }
3828  
3829      /**
3830       * Test returning contacts with unread message count.
3831       * MDL-69643
3832       */
3833      public function test_get_contacts_with_unread_message_count() {
3834          global $DB;
3835  
3836          $user1 = self::getDataGenerator()->create_user();
3837          $user2 = self::getDataGenerator()->create_user();
3838          $user3 = self::getDataGenerator()->create_user();
3839          $user4 = self::getDataGenerator()->create_user();
3840  
3841          // Add the users to each of their contacts.
3842          api::add_contact($user1->id, $user2->id);
3843          api::add_contact($user2->id, $user3->id);
3844  
3845          $this->send_fake_message($user1, $user2);
3846          $this->send_fake_message($user1, $user2);
3847          $this->send_fake_message($user1, $user2);
3848          $message4id = $this->send_fake_message($user1, $user2);
3849  
3850          $this->send_fake_message($user3, $user2);
3851          $message6id = $this->send_fake_message($user3, $user2);
3852          $this->send_fake_message($user3, $user2);
3853          $this->send_fake_message($user3, $user2);
3854          $this->send_fake_message($user3, $user2);
3855  
3856          // Send a message that should never be included as the user is not a contact.
3857          $this->send_fake_message($user4, $user2);
3858  
3859          // Get the contacts and the unread message count.
3860          $messages = api::get_contacts_with_unread_message_count($user2->id);
3861          $this->assertDebuggingCalled();
3862  
3863          // Confirm the size is correct.
3864          $this->assertCount(2, $messages);
3865          ksort($messages);
3866  
3867          $messageinfo1 = array_shift($messages);
3868          $messageinfo2 = array_shift($messages);
3869  
3870          $this->assertEquals($user1->id, $messageinfo1->id);
3871          $this->assertEquals(4, $messageinfo1->messagecount);
3872          $this->assertEquals($user3->id, $messageinfo2->id);
3873          $this->assertEquals(5, $messageinfo2->messagecount);
3874  
3875          // Mark some of the messages as read.
3876          $m4 = $DB->get_record('messages', ['id' => $message4id]);
3877          $m6 = $DB->get_record('messages', ['id' => $message6id]);
3878          api::mark_message_as_read($user2->id, $m4);
3879          api::mark_message_as_read($user2->id, $m6);
3880  
3881          // Get the contacts and the unread message count.
3882          $messages = api::get_contacts_with_unread_message_count($user2->id);
3883          $this->assertDebuggingCalled();
3884  
3885          // Confirm the size is correct.
3886          $this->assertCount(2, $messages);
3887          ksort($messages);
3888  
3889          // Confirm read messages are not included.
3890          $messageinfo1 = array_shift($messages);
3891          $messageinfo2 = array_shift($messages);
3892          $this->assertEquals($user1->id, $messageinfo1->id);
3893          $this->assertEquals(3, $messageinfo1->messagecount);
3894          $this->assertEquals($user3->id, $messageinfo2->id);
3895          $this->assertEquals(4, $messageinfo2->messagecount);
3896  
3897          // Now, let's populate the database with messages from user2 to user 1.
3898          $this->send_fake_message($user2, $user1);
3899          $this->send_fake_message($user2, $user1);
3900          $messageid = $this->send_fake_message($user2, $user1);
3901  
3902          // Send a message that should never be included as the user is not a contact.
3903          $this->send_fake_message($user4, $user1);
3904  
3905          // Get the contacts and the unread message count.
3906          $messages = api::get_contacts_with_unread_message_count($user1->id);
3907          $this->assertDebuggingCalled();
3908  
3909          // Confirm the size is correct.
3910          $this->assertCount(1, $messages);
3911          $messageinfo1 = array_shift($messages);
3912          $this->assertEquals($user2->id, $messageinfo1->id);
3913          $this->assertEquals(3, $messageinfo1->messagecount);
3914  
3915          // Mark the last message as read.
3916          $m = $DB->get_record('messages', ['id' => $messageid]);
3917          api::mark_message_as_read($user1->id, $m);
3918  
3919          $messages = api::get_contacts_with_unread_message_count($user1->id);
3920          $this->assertDebuggingCalled();
3921  
3922          // Confirm the size is correct.
3923          $this->assertCount(1, $messages);
3924  
3925          // Confirm read messages are not included.
3926          $messageinfo1 = array_shift($messages);
3927          $this->assertEquals($user2->id, $messageinfo1->id);
3928          $this->assertEquals(2, $messageinfo1->messagecount);
3929      }
3930  
3931      /**
3932       * Test returning contacts with unread message count when there are no messages.
3933       */
3934      public function test_get_contacts_with_unread_message_count_no_messages() {
3935          $user1 = self::getDataGenerator()->create_user();
3936          $user2 = self::getDataGenerator()->create_user();
3937  
3938          // Add the users to each of their contacts.
3939          api::add_contact($user2->id, $user1->id);
3940  
3941          // Check we get the correct message count.
3942          $messages = api::get_contacts_with_unread_message_count($user2->id);
3943          $this->assertDebuggingCalled();
3944  
3945          // Confirm the size is correct.
3946          $this->assertCount(1, $messages);
3947  
3948          $messageinfo = array_shift($messages);
3949  
3950          $this->assertEquals($user1->id, $messageinfo->id);
3951          $this->assertEquals(0, $messageinfo->messagecount);
3952      }
3953  
3954      /**
3955       * Test returning non-contacts with unread message count.
3956       * MDL-69643
3957       */
3958      public function test_get_non_contacts_with_unread_message_count() {
3959          global $DB;
3960  
3961          $user1 = self::getDataGenerator()->create_user();
3962          $user2 = self::getDataGenerator()->create_user();
3963          $user3 = self::getDataGenerator()->create_user();
3964          $user4 = self::getDataGenerator()->create_user();
3965  
3966          // Add a user to the contact list of the users we are testing this function with.
3967          api::add_contact($user1->id, $user4->id);
3968          api::add_contact($user2->id, $user4->id);
3969  
3970          $this->send_fake_message($user1, $user2);
3971          $this->send_fake_message($user1, $user2);
3972          $this->send_fake_message($user1, $user2);
3973          $message4id = $this->send_fake_message($user1, $user2);
3974  
3975          $this->send_fake_message($user3, $user2);
3976          $message6id = $this->send_fake_message($user3, $user2);
3977          $this->send_fake_message($user3, $user2);
3978          $this->send_fake_message($user3, $user2);
3979          $this->send_fake_message($user3, $user2);
3980  
3981          // Send a message that should never be included as the user is a contact.
3982          $this->send_fake_message($user4, $user2);
3983  
3984  
3985          // Get the non-contacts and the unread message count.
3986          $messages = api::get_non_contacts_with_unread_message_count($user2->id);
3987          $this->assertDebuggingCalled();
3988  
3989          // Check we get the correct message count.
3990          ksort($messages);
3991          $this->assertCount(2, $messages);
3992          $messageinfo1 = array_shift($messages);
3993          $messageinfo2 = array_shift($messages);
3994          $this->assertEquals($user1->id, $messageinfo1->id);
3995          $this->assertEquals(4, $messageinfo1->messagecount);
3996          $this->assertEquals($user3->id, $messageinfo2->id);
3997          $this->assertEquals(5, $messageinfo2->messagecount);
3998  
3999          // Mark some of the messages as read.
4000          $m4 = $DB->get_record('messages', ['id' => $message4id]);
4001          $m6 = $DB->get_record('messages', ['id' => $message6id]);
4002          api::mark_message_as_read($user2->id, $m4);
4003          api::mark_message_as_read($user2->id, $m6);
4004  
4005          // Get the non-contacts and the unread message count.
4006          $messages = api::get_non_contacts_with_unread_message_count($user2->id);
4007          $this->assertDebuggingCalled();
4008  
4009          // Check the marked message is not returned in the message count.
4010          ksort($messages);
4011          $this->assertCount(2, $messages);
4012          $messageinfo1 = array_shift($messages);
4013          $messageinfo2 = array_shift($messages);
4014          $this->assertEquals($user1->id, $messageinfo1->id);
4015          $this->assertEquals(3, $messageinfo1->messagecount);
4016          $this->assertEquals($user3->id, $messageinfo2->id);
4017          $this->assertEquals(4, $messageinfo2->messagecount);
4018  
4019          // Now, let's populate the database with messages from user2 to user 1.
4020          $this->send_fake_message($user2, $user1);
4021          $this->send_fake_message($user2, $user1);
4022          $messageid = $this->send_fake_message($user2, $user1);
4023  
4024          // Send a message that should never be included as the user is a contact.
4025          $this->send_fake_message($user4, $user1);
4026  
4027          // Get the non-contacts and the unread message count.
4028          $messages = api::get_non_contacts_with_unread_message_count($user1->id);
4029          $this->assertDebuggingCalled();
4030  
4031          // Confirm the size is correct.
4032          $this->assertCount(1, $messages);
4033          $messageinfo1 = array_shift($messages);
4034          $this->assertEquals($user2->id, $messageinfo1->id);
4035          $this->assertEquals(3, $messageinfo1->messagecount);
4036  
4037          // Mark the last message as read.
4038          $m = $DB->get_record('messages', ['id' => $messageid]);
4039          api::mark_message_as_read($user1->id, $m);
4040  
4041          // Get the non-contacts and the unread message count.
4042          $messages = api::get_non_contacts_with_unread_message_count($user1->id);
4043          $this->assertDebuggingCalled();
4044  
4045          // Check the marked message is not returned in the message count.
4046          $this->assertCount(1, $messages);
4047          $messageinfo1 = array_shift($messages);
4048          $this->assertEquals($user2->id, $messageinfo1->id);
4049          $this->assertEquals(2, $messageinfo1->messagecount);
4050      }
4051  
4052      /**
4053       * Test marking a message as read.
4054       */
4055      public function test_mark_message_as_read() {
4056          global $DB;
4057  
4058          $user1 = self::getDataGenerator()->create_user();
4059          $user2 = self::getDataGenerator()->create_user();
4060  
4061          $this->send_fake_message($user1, $user2);
4062          $m2id = $this->send_fake_message($user1, $user2);
4063          $this->send_fake_message($user2, $user1);
4064          $m4id = $this->send_fake_message($user2, $user1);
4065  
4066          $m2 = $DB->get_record('messages', ['id' => $m2id]);
4067          $m4 = $DB->get_record('messages', ['id' => $m4id]);
4068          api::mark_message_as_read($user2->id, $m2, 11);
4069          api::mark_message_as_read($user1->id, $m4, 12);
4070  
4071          // Confirm there are two user actions.
4072          $muas = $DB->get_records('message_user_actions', [], 'timecreated ASC');
4073          $this->assertEquals(2, count($muas));
4074  
4075          // Confirm they are correct.
4076          $mua1 = array_shift($muas);
4077          $mua2 = array_shift($muas);
4078  
4079          // Confirm first action.
4080          $this->assertEquals($user2->id, $mua1->userid);
4081          $this->assertEquals($m2id, $mua1->messageid);
4082          $this->assertEquals(api::MESSAGE_ACTION_READ, $mua1->action);
4083          $this->assertEquals(11, $mua1->timecreated);
4084  
4085          // Confirm second action.
4086          $this->assertEquals($user1->id, $mua2->userid);
4087          $this->assertEquals($m4id, $mua2->messageid);
4088          $this->assertEquals(api::MESSAGE_ACTION_READ, $mua2->action);
4089          $this->assertEquals(12, $mua2->timecreated);
4090      }
4091  
4092      /**
4093       * Test marking a notification as read.
4094       */
4095      public function test_mark_notification_as_read() {
4096          global $DB;
4097  
4098          $user1 = self::getDataGenerator()->create_user();
4099          $user2 = self::getDataGenerator()->create_user();
4100  
4101          $this->send_fake_message($user1, $user2, 'Notification 1', 1);
4102          $n2id = $this->send_fake_message($user1, $user2, 'Notification 2', 1);
4103          $this->send_fake_message($user2, $user1, 'Notification 3', 1);
4104          $n4id = $this->send_fake_message($user2, $user1, 'Notification 4', 1);
4105  
4106          $n2 = $DB->get_record('notifications', ['id' => $n2id]);
4107          $n4 = $DB->get_record('notifications', ['id' => $n4id]);
4108  
4109          api::mark_notification_as_read($n2, 11);
4110          api::mark_notification_as_read($n4, 12);
4111  
4112          // Retrieve the notifications.
4113          $n2 = $DB->get_record('notifications', ['id' => $n2id]);
4114          $n4 = $DB->get_record('notifications', ['id' => $n4id]);
4115  
4116          // Confirm they have been marked as read.
4117          $this->assertEquals(11, $n2->timeread);
4118          $this->assertEquals(12, $n4->timeread);
4119      }
4120  
4121      /**
4122       * Test a conversation is not returned if there is none.
4123       */
4124      public function test_get_conversation_between_users_no_conversation() {
4125          $user1 = self::getDataGenerator()->create_user();
4126          $user2 = self::getDataGenerator()->create_user();
4127  
4128          $this->assertFalse(api::get_conversation_between_users([$user1->id, $user2->id]));
4129      }
4130  
4131      /**
4132       * Test count_conversation_members for non existing conversation.
4133       */
4134      public function test_count_conversation_members_no_existing_conversation() {
4135          $this->assertEquals(0,
4136              api::count_conversation_members(0));
4137      }
4138  
4139      /**
4140       * Test count_conversation_members for existing conversation.
4141       */
4142      public function test_count_conversation_members_existing_conversation() {
4143          $user1 = self::getDataGenerator()->create_user();
4144          $user2 = self::getDataGenerator()->create_user();
4145  
4146          $conversation = api::create_conversation(
4147              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
4148              [
4149                  $user1->id,
4150                  $user2->id
4151              ]
4152          );
4153          $conversationid = $conversation->id;
4154  
4155          $this->assertEquals(2,
4156              api::count_conversation_members($conversationid));
4157      }
4158  
4159      /**
4160       * Test add_members_to_conversation for an individual conversation.
4161       */
4162      public function test_add_members_to_individual_conversation() {
4163          $user1 = self::getDataGenerator()->create_user();
4164          $user2 = self::getDataGenerator()->create_user();
4165          $user3 = self::getDataGenerator()->create_user();
4166  
4167          $conversation = api::create_conversation(
4168              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
4169              [
4170                  $user1->id,
4171                  $user2->id
4172              ]
4173          );
4174          $conversationid = $conversation->id;
4175  
4176          $this->expectException('moodle_exception');
4177          api::add_members_to_conversation([$user3->id], $conversationid);
4178      }
4179  
4180      /**
4181       * Test add_members_to_conversation for existing conversation.
4182       */
4183      public function test_add_members_to_existing_conversation() {
4184          $user1 = self::getDataGenerator()->create_user();
4185          $user2 = self::getDataGenerator()->create_user();
4186          $user3 = self::getDataGenerator()->create_user();
4187  
4188          $conversation = api::create_conversation(
4189              api::MESSAGE_CONVERSATION_TYPE_GROUP,
4190              [
4191                  $user1->id,
4192                  $user2->id
4193              ]
4194          );
4195          $conversationid = $conversation->id;
4196  
4197          $this->assertNull(api::add_members_to_conversation([$user3->id], $conversationid));
4198          $this->assertEquals(3,
4199              api::count_conversation_members($conversationid));
4200      }
4201  
4202      /**
4203       * Test add_members_to_conversation for non existing conversation.
4204       */
4205      public function test_add_members_to_no_existing_conversation() {
4206          $user1 = self::getDataGenerator()->create_user();
4207  
4208          // Throw dml_missing_record_exception for non existing conversation.
4209          $this->expectException('dml_missing_record_exception');
4210          api::add_members_to_conversation([$user1->id], 0);
4211      }
4212  
4213      /**
4214       * Test add_member_to_conversation for non existing user.
4215       */
4216      public function test_add_members_to_no_existing_user() {
4217          $user1 = self::getDataGenerator()->create_user();
4218          $user2 = self::getDataGenerator()->create_user();
4219  
4220          $conversation = api::create_conversation(
4221              api::MESSAGE_CONVERSATION_TYPE_GROUP,
4222              [
4223                  $user1->id,
4224                  $user2->id
4225              ]
4226          );
4227          $conversationid = $conversation->id;
4228  
4229          // Don't throw an error for non existing user, but don't add it as a member.
4230          $this->assertNull(api::add_members_to_conversation([0], $conversationid));
4231          $this->assertEquals(2,
4232              api::count_conversation_members($conversationid));
4233      }
4234  
4235      /**
4236       * Test add_members_to_conversation for current conversation member.
4237       */
4238      public function test_add_members_to_current_conversation_member() {
4239          $user1 = self::getDataGenerator()->create_user();
4240          $user2 = self::getDataGenerator()->create_user();
4241  
4242          $conversation = api::create_conversation(
4243              api::MESSAGE_CONVERSATION_TYPE_GROUP,
4244              [
4245                  $user1->id,
4246                  $user2->id
4247              ]
4248          );
4249          $conversationid = $conversation->id;
4250  
4251          // Don't add as a member a user that is already conversation member.
4252          $this->assertNull(api::add_members_to_conversation([$user1->id], $conversationid));
4253          $this->assertEquals(2,
4254              api::count_conversation_members($conversationid));
4255      }
4256  
4257      /**
4258       * Test add_members_to_conversation for multiple users.
4259       */
4260      public function test_add_members_for_multiple_users() {
4261          $user1 = self::getDataGenerator()->create_user();
4262          $user2 = self::getDataGenerator()->create_user();
4263          $user3 = self::getDataGenerator()->create_user();
4264          $user4 = self::getDataGenerator()->create_user();
4265  
4266          $conversation = api::create_conversation(
4267              api::MESSAGE_CONVERSATION_TYPE_GROUP,
4268              [
4269                  $user1->id,
4270                  $user2->id
4271              ]
4272          );
4273          $conversationid = $conversation->id;
4274  
4275          $this->assertNull(api::add_members_to_conversation([$user3->id, $user4->id], $conversationid));
4276          $this->assertEquals(4,
4277              api::count_conversation_members($conversationid));
4278      }
4279  
4280      /**
4281       * Test add_members_to_conversation for multiple users, included non existing and current conversation members
4282       */
4283      public function test_add_members_for_multiple_not_valid_users() {
4284          $user1 = self::getDataGenerator()->create_user();
4285          $user2 = self::getDataGenerator()->create_user();
4286          $user3 = self::getDataGenerator()->create_user();
4287  
4288          $conversation = api::create_conversation(
4289              api::MESSAGE_CONVERSATION_TYPE_GROUP,
4290              [
4291                  $user1->id,
4292                  $user2->id
4293              ]
4294          );
4295          $conversationid = $conversation->id;
4296  
4297          // Don't throw errors, but don't add as members users don't exist or are already conversation members.
4298          $this->assertNull(api::add_members_to_conversation([$user3->id, $user1->id, 0], $conversationid));
4299          $this->assertEquals(3,
4300              api::count_conversation_members($conversationid));
4301      }
4302  
4303      /**
4304       * Test remove_members_from_conversation for individual conversation.
4305       */
4306      public function test_remove_members_from_individual_conversation() {
4307          $user1 = self::getDataGenerator()->create_user();
4308          $user2 = self::getDataGenerator()->create_user();
4309  
4310          $conversation = api::create_conversation(
4311              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
4312              [
4313                  $user1->id,
4314                  $user2->id
4315              ]
4316          );
4317          $conversationid = $conversation->id;
4318  
4319          $this->expectException('moodle_exception');
4320          api::remove_members_from_conversation([$user1->id], $conversationid);
4321      }
4322  
4323      /**
4324       * Test remove_members_from_conversation for existing conversation.
4325       */
4326      public function test_remove_members_from_existing_conversation() {
4327          $user1 = self::getDataGenerator()->create_user();
4328          $user2 = self::getDataGenerator()->create_user();
4329  
4330          $conversation = api::create_conversation(
4331              api::MESSAGE_CONVERSATION_TYPE_GROUP,
4332              [
4333                  $user1->id,
4334                  $user2->id
4335              ]
4336          );
4337          $conversationid = $conversation->id;
4338  
4339          $this->assertNull(api::remove_members_from_conversation([$user1->id], $conversationid));
4340          $this->assertEquals(1,
4341              api::count_conversation_members($conversationid));
4342      }
4343  
4344      /**
4345       * Test remove_members_from_conversation for non existing conversation.
4346       */
4347      public function test_remove_members_from_no_existing_conversation() {
4348          $user1 = self::getDataGenerator()->create_user();
4349  
4350          // Throw dml_missing_record_exception for non existing conversation.
4351          $this->expectException('dml_missing_record_exception');
4352          api::remove_members_from_conversation([$user1->id], 0);
4353      }
4354  
4355      /**
4356       * Test remove_members_from_conversation for non existing user.
4357       */
4358      public function test_remove_members_for_no_existing_user() {
4359          $user1 = self::getDataGenerator()->create_user();
4360          $user2 = self::getDataGenerator()->create_user();
4361  
4362          $conversation = api::create_conversation(
4363              api::MESSAGE_CONVERSATION_TYPE_GROUP,
4364              [
4365                  $user1->id,
4366                  $user2->id
4367              ]
4368          );
4369          $conversationid = $conversation->id;
4370  
4371          $this->assertNull(api::remove_members_from_conversation([0], $conversationid));
4372          $this->assertEquals(2,
4373              api::count_conversation_members($conversationid));
4374      }
4375  
4376      /**
4377       * Test remove_members_from_conversation for multiple users.
4378       */
4379      public function test_remove_members_for_multiple_users() {
4380          $user1 = self::getDataGenerator()->create_user();
4381          $user2 = self::getDataGenerator()->create_user();
4382          $user3 = self::getDataGenerator()->create_user();
4383          $user4 = self::getDataGenerator()->create_user();
4384  
4385          $conversation = api::create_conversation(
4386              api::MESSAGE_CONVERSATION_TYPE_GROUP,
4387              [
4388                  $user1->id,
4389                  $user2->id
4390              ]
4391          );
4392          $conversationid = $conversation->id;
4393  
4394          $this->assertNull(api::add_members_to_conversation([$user3->id, $user4->id], $conversationid));
4395          $this->assertNull(api::remove_members_from_conversation([$user3->id, $user4->id], $conversationid));
4396          $this->assertEquals(2,
4397              api::count_conversation_members($conversationid));
4398      }
4399  
4400      /**
4401       * Test remove_members_from_conversation for multiple non valid users.
4402       */
4403      public function test_remove_members_for_multiple_no_valid_users() {
4404          $user1 = self::getDataGenerator()->create_user();
4405          $user2 = self::getDataGenerator()->create_user();
4406          $user3 = self::getDataGenerator()->create_user();
4407          $user4 = self::getDataGenerator()->create_user();
4408  
4409          $conversation = api::create_conversation(
4410              api::MESSAGE_CONVERSATION_TYPE_GROUP,
4411              [
4412                  $user1->id,
4413                  $user2->id
4414              ]
4415          );
4416          $conversationid = $conversation->id;
4417  
4418          $this->assertNull(api::add_members_to_conversation([$user3->id], $conversationid));
4419          $this->assertNull(
4420              api::remove_members_from_conversation([$user2->id, $user3->id, $user4->id, 0], $conversationid)
4421          );
4422          $this->assertEquals(1,
4423              api::count_conversation_members($conversationid));
4424      }
4425  
4426      /**
4427       * Test count_conversation_members for empty conversation.
4428       */
4429      public function test_count_conversation_members_empty_conversation() {
4430          $user1 = self::getDataGenerator()->create_user();
4431          $user2 = self::getDataGenerator()->create_user();
4432  
4433          $conversation = api::create_conversation(
4434              api::MESSAGE_CONVERSATION_TYPE_GROUP,
4435              [
4436                  $user1->id,
4437                  $user2->id
4438              ]
4439          );
4440          $conversationid = $conversation->id;
4441  
4442          $this->assertNull(api::remove_members_from_conversation([$user1->id, $user2->id], $conversationid));
4443  
4444          $this->assertEquals(0,
4445              api::count_conversation_members($conversationid));
4446      }
4447  
4448      /**
4449       * Test can create a contact request.
4450       */
4451      public function test_can_create_contact_request() {
4452          global $CFG;
4453  
4454          $user1 = self::getDataGenerator()->create_user();
4455          $user2 = self::getDataGenerator()->create_user();
4456  
4457          // Disable messaging.
4458          $CFG->messaging = 0;
4459          $this->assertFalse(api::can_create_contact($user1->id, $user2->id));
4460  
4461          // Re-enable messaging.
4462          $CFG->messaging = 1;
4463  
4464          // Allow users to message anyone site-wide.
4465          $CFG->messagingallusers = 1;
4466          $this->assertTrue(api::can_create_contact($user1->id, $user2->id));
4467  
4468          // Disallow users from messaging anyone site-wide.
4469          $CFG->messagingallusers = 0;
4470          $this->assertFalse(api::can_create_contact($user1->id, $user2->id));
4471  
4472          // Put the users in the same course so a contact request should be possible.
4473          $course = self::getDataGenerator()->create_course();
4474          $this->getDataGenerator()->enrol_user($user1->id, $course->id);
4475          $this->getDataGenerator()->enrol_user($user2->id, $course->id);
4476          $this->assertTrue(api::can_create_contact($user1->id, $user2->id));
4477      }
4478  
4479      /**
4480       * Test creating a contact request.
4481       */
4482      public function test_create_contact_request() {
4483          global $DB;
4484  
4485          $user1 = self::getDataGenerator()->create_user();
4486          $user2 = self::getDataGenerator()->create_user();
4487  
4488          $sink = $this->redirectMessages();
4489          $request = api::create_contact_request($user1->id, $user2->id);
4490          $messages = $sink->get_messages();
4491          $sink->close();
4492          // Test customdata.
4493          $customdata = json_decode($messages[0]->customdata);
4494          $this->assertObjectHasAttribute('notificationiconurl', $customdata);
4495          $this->assertObjectHasAttribute('actionbuttons', $customdata);
4496          $this->assertCount(2, (array) $customdata->actionbuttons);
4497  
4498          $this->assertEquals($user1->id, $request->userid);
4499          $this->assertEquals($user2->id, $request->requesteduserid);
4500      }
4501  
4502      /**
4503       * Test confirming a contact request.
4504       */
4505      public function test_confirm_contact_request() {
4506          global $DB;
4507  
4508          $user1 = self::getDataGenerator()->create_user();
4509          $user2 = self::getDataGenerator()->create_user();
4510  
4511          api::create_contact_request($user1->id, $user2->id);
4512  
4513          api::confirm_contact_request($user1->id, $user2->id);
4514  
4515          $this->assertEquals(0, $DB->count_records('message_contact_requests'));
4516  
4517          $contact = $DB->get_records('message_contacts');
4518  
4519          $this->assertCount(1, $contact);
4520  
4521          $contact = reset($contact);
4522  
4523          $this->assertEquals($user1->id, $contact->userid);
4524          $this->assertEquals($user2->id, $contact->contactid);
4525      }
4526  
4527      /**
4528       * Test declining a contact request.
4529       */
4530      public function test_decline_contact_request() {
4531          global $DB;
4532  
4533          $user1 = self::getDataGenerator()->create_user();
4534          $user2 = self::getDataGenerator()->create_user();
4535  
4536          api::create_contact_request($user1->id, $user2->id);
4537  
4538          api::decline_contact_request($user1->id, $user2->id);
4539  
4540          $this->assertEquals(0, $DB->count_records('message_contact_requests'));
4541          $this->assertEquals(0, $DB->count_records('message_contacts'));
4542      }
4543  
4544      /**
4545       * Test retrieving contact requests.
4546       */
4547      public function test_get_contact_requests() {
4548          global $PAGE;
4549  
4550          $user1 = self::getDataGenerator()->create_user();
4551          $user2 = self::getDataGenerator()->create_user();
4552          $user3 = self::getDataGenerator()->create_user();
4553  
4554          // Block one user, their request should not show up.
4555          api::block_user($user1->id, $user3->id);
4556  
4557          api::create_contact_request($user2->id, $user1->id);
4558          api::create_contact_request($user3->id, $user1->id);
4559  
4560          $requests = api::get_contact_requests($user1->id);
4561  
4562          $this->assertCount(1, $requests);
4563  
4564          $request = reset($requests);
4565          $userpicture = new \user_picture($user2);
4566          $profileimageurl = $userpicture->get_url($PAGE)->out(false);
4567  
4568          $this->assertEquals($user2->id, $request->id);
4569          $this->assertEquals(fullname($user2), $request->fullname);
4570          $this->assertObjectHasAttribute('profileimageurl', $request);
4571          $this->assertObjectHasAttribute('profileimageurlsmall', $request);
4572          $this->assertObjectHasAttribute('isonline', $request);
4573          $this->assertObjectHasAttribute('showonlinestatus', $request);
4574          $this->assertObjectHasAttribute('isblocked', $request);
4575          $this->assertObjectHasAttribute('iscontact', $request);
4576      }
4577  
4578      /**
4579       * Test the get_contact_requests() function when the user has blocked the sender of the request.
4580       */
4581      public function test_get_contact_requests_blocked_sender() {
4582          $user1 = self::getDataGenerator()->create_user();
4583          $user2 = self::getDataGenerator()->create_user();
4584  
4585          // User1 blocks User2.
4586          api::block_user($user1->id, $user2->id);
4587  
4588          // User2 tries to add User1 as a contact.
4589          api::create_contact_request($user2->id, $user1->id);
4590  
4591          // Verify we don't see the contact request from the blocked user User2 in the requests for User1.
4592          $requests = api::get_contact_requests($user1->id);
4593          $this->assertEmpty($requests);
4594      }
4595  
4596      /**
4597       * Test getting contact requests when there are none.
4598       */
4599      public function test_get_contact_requests_no_requests() {
4600          $this->resetAfterTest();
4601  
4602          $user1 = self::getDataGenerator()->create_user();
4603  
4604          $requests = api::get_contact_requests($user1->id);
4605  
4606          $this->assertEmpty($requests);
4607      }
4608  
4609      /**
4610       * Test getting contact requests with limits.
4611       */
4612      public function test_get_contact_requests_with_limits() {
4613          $this->resetAfterTest();
4614  
4615          $user1 = self::getDataGenerator()->create_user();
4616          $user2 = self::getDataGenerator()->create_user();
4617          $user3 = self::getDataGenerator()->create_user();
4618  
4619          api::create_contact_request($user2->id, $user1->id);
4620          api::create_contact_request($user3->id, $user1->id);
4621  
4622          $requests = api::get_contact_requests($user1->id, 0, 1);
4623  
4624          $this->assertCount(1, $requests);
4625      }
4626  
4627      /**
4628       * Test adding contacts.
4629       */
4630      public function test_add_contact() {
4631          global $DB;
4632  
4633          $user1 = self::getDataGenerator()->create_user();
4634          $user2 = self::getDataGenerator()->create_user();
4635  
4636          api::add_contact($user1->id, $user2->id);
4637  
4638          $contact = $DB->get_records('message_contacts');
4639  
4640          $this->assertCount(1, $contact);
4641  
4642          $contact = reset($contact);
4643  
4644          $this->assertEquals($user1->id, $contact->userid);
4645          $this->assertEquals($user2->id, $contact->contactid);
4646      }
4647  
4648      /**
4649       * Test removing contacts.
4650       */
4651      public function test_remove_contact() {
4652          global $DB;
4653  
4654          $user1 = self::getDataGenerator()->create_user();
4655          $user2 = self::getDataGenerator()->create_user();
4656  
4657          api::add_contact($user1->id, $user2->id);
4658          api::remove_contact($user1->id, $user2->id);
4659  
4660          $this->assertEquals(0, $DB->count_records('message_contacts'));
4661      }
4662  
4663      /**
4664       * Test blocking users.
4665       */
4666      public function test_block_user() {
4667          global $DB;
4668  
4669          $user1 = self::getDataGenerator()->create_user();
4670          $user2 = self::getDataGenerator()->create_user();
4671  
4672          api::block_user($user1->id, $user2->id);
4673  
4674          $blockedusers = $DB->get_records('message_users_blocked');
4675  
4676          $this->assertCount(1, $blockedusers);
4677  
4678          $blockeduser = reset($blockedusers);
4679  
4680          $this->assertEquals($user1->id, $blockeduser->userid);
4681          $this->assertEquals($user2->id, $blockeduser->blockeduserid);
4682      }
4683  
4684      /**
4685       * Test unblocking users.
4686       */
4687      public function test_unblock_user() {
4688          global $DB;
4689  
4690          $user1 = self::getDataGenerator()->create_user();
4691          $user2 = self::getDataGenerator()->create_user();
4692  
4693          api::block_user($user1->id, $user2->id);
4694          api::unblock_user($user1->id, $user2->id);
4695  
4696          $this->assertEquals(0, $DB->count_records('message_users_blocked'));
4697      }
4698  
4699      /**
4700       * Test muting a conversation.
4701       */
4702      public function test_mute_conversation() {
4703          global $DB;
4704  
4705          $user1 = self::getDataGenerator()->create_user();
4706          $user2 = self::getDataGenerator()->create_user();
4707  
4708          $conversation = api::create_conversation(
4709              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
4710              [
4711                  $user1->id,
4712                  $user2->id
4713              ]
4714          );
4715          $conversationid = $conversation->id;
4716  
4717          api::mute_conversation($user1->id, $conversationid);
4718  
4719          $mutedconversation = $DB->get_records('message_conversation_actions');
4720  
4721          $this->assertCount(1, $mutedconversation);
4722  
4723          $mutedconversation = reset($mutedconversation);
4724  
4725          $this->assertEquals($user1->id, $mutedconversation->userid);
4726          $this->assertEquals($conversationid, $mutedconversation->conversationid);
4727          $this->assertEquals(api::CONVERSATION_ACTION_MUTED, $mutedconversation->action);
4728      }
4729  
4730      /**
4731       * Test unmuting a conversation.
4732       */
4733      public function test_unmute_conversation() {
4734          global $DB;
4735  
4736          $user1 = self::getDataGenerator()->create_user();
4737          $user2 = self::getDataGenerator()->create_user();
4738  
4739          $conversation = api::create_conversation(
4740              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
4741              [
4742                  $user1->id,
4743                  $user2->id
4744              ]
4745          );
4746          $conversationid = $conversation->id;
4747  
4748          api::mute_conversation($user1->id, $conversationid);
4749          api::unmute_conversation($user1->id, $conversationid);
4750  
4751          $this->assertEquals(0, $DB->count_records('message_conversation_actions'));
4752      }
4753  
4754      /**
4755       * Test if a conversation is muted.
4756       */
4757      public function test_is_conversation_muted() {
4758          $user1 = self::getDataGenerator()->create_user();
4759          $user2 = self::getDataGenerator()->create_user();
4760  
4761          $conversation = api::create_conversation(
4762              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
4763              [
4764                  $user1->id,
4765                  $user2->id
4766              ]
4767          );
4768          $conversationid = $conversation->id;
4769  
4770          $this->assertFalse(api::is_conversation_muted($user1->id, $conversationid));
4771  
4772          api::mute_conversation($user1->id, $conversationid);
4773  
4774          $this->assertTrue(api::is_conversation_muted($user1->id, $conversationid));
4775      }
4776  
4777      /**
4778       * Test is contact check.
4779       */
4780      public function test_is_contact() {
4781          $user1 = self::getDataGenerator()->create_user();
4782          $user2 = self::getDataGenerator()->create_user();
4783          $user3 = self::getDataGenerator()->create_user();
4784  
4785          api::add_contact($user1->id, $user2->id);
4786  
4787          $this->assertTrue(api::is_contact($user1->id, $user2->id));
4788          $this->assertTrue(api::is_contact($user2->id, $user1->id));
4789          $this->assertFalse(api::is_contact($user2->id, $user3->id));
4790      }
4791  
4792      /**
4793       * Test get contact.
4794       */
4795      public function test_get_contact() {
4796          $user1 = self::getDataGenerator()->create_user();
4797          $user2 = self::getDataGenerator()->create_user();
4798  
4799          api::add_contact($user1->id, $user2->id);
4800  
4801          $contact = api::get_contact($user1->id, $user2->id);
4802  
4803          $this->assertEquals($user1->id, $contact->userid);
4804          $this->assertEquals($user2->id, $contact->contactid);
4805      }
4806  
4807      /**
4808       * Test is blocked checked.
4809       */
4810      public function test_is_blocked() {
4811          $user1 = self::getDataGenerator()->create_user();
4812          $user2 = self::getDataGenerator()->create_user();
4813  
4814          $this->assertFalse(api::is_blocked($user1->id, $user2->id));
4815          $this->assertFalse(api::is_blocked($user2->id, $user1->id));
4816  
4817          api::block_user($user1->id, $user2->id);
4818  
4819          $this->assertTrue(api::is_blocked($user1->id, $user2->id));
4820          $this->assertFalse(api::is_blocked($user2->id, $user1->id));
4821      }
4822  
4823      /**
4824       * Test the contact request exist check.
4825       */
4826      public function test_does_contact_request_exist() {
4827          $user1 = self::getDataGenerator()->create_user();
4828          $user2 = self::getDataGenerator()->create_user();
4829  
4830          $this->assertFalse(api::does_contact_request_exist($user1->id, $user2->id));
4831          $this->assertFalse(api::does_contact_request_exist($user2->id, $user1->id));
4832  
4833          api::create_contact_request($user1->id, $user2->id);
4834  
4835          $this->assertTrue(api::does_contact_request_exist($user1->id, $user2->id));
4836          $this->assertTrue(api::does_contact_request_exist($user2->id, $user1->id));
4837      }
4838  
4839      /**
4840       * Test the get_received_contact_requests_count() function.
4841       */
4842      public function test_get_received_contact_requests_count() {
4843          $user1 = self::getDataGenerator()->create_user();
4844          $user2 = self::getDataGenerator()->create_user();
4845          $user3 = self::getDataGenerator()->create_user();
4846          $user4 = self::getDataGenerator()->create_user();
4847  
4848          $this->assertEquals(0, api::get_received_contact_requests_count($user1->id));
4849  
4850          api::create_contact_request($user2->id, $user1->id);
4851  
4852          $this->assertEquals(1, api::get_received_contact_requests_count($user1->id));
4853  
4854          api::create_contact_request($user3->id, $user1->id);
4855  
4856          $this->assertEquals(2, api::get_received_contact_requests_count($user1->id));
4857  
4858          api::create_contact_request($user1->id, $user4->id);
4859          // Function should ignore sent requests.
4860          $this->assertEquals(2, api::get_received_contact_requests_count($user1->id));
4861      }
4862  
4863      /**
4864       * Test the get_received_contact_requests_count() function when the user has blocked the sender of the request.
4865       */
4866      public function test_get_received_contact_requests_count_blocked_sender() {
4867          $user1 = self::getDataGenerator()->create_user();
4868          $user2 = self::getDataGenerator()->create_user();
4869  
4870          // User1 blocks User2.
4871          api::block_user($user1->id, $user2->id);
4872  
4873          // User2 tries to add User1 as a contact.
4874          api::create_contact_request($user2->id, $user1->id);
4875  
4876          // Verify we don't see the contact request from the blocked user User2 in the count for User1.
4877          $this->assertEquals(0, api::get_received_contact_requests_count($user1->id));
4878      }
4879  
4880      /**
4881       * Test the get_contact_requests_between_users() function.
4882       */
4883      public function test_get_contact_requests_between_users() {
4884          $user1 = self::getDataGenerator()->create_user();
4885          $user2 = self::getDataGenerator()->create_user();
4886          $user3 = self::getDataGenerator()->create_user();
4887          $user4 = self::getDataGenerator()->create_user();
4888  
4889          $this->assertEquals([], api::get_contact_requests_between_users($user1->id, $user2->id));
4890  
4891          $request1 = api::create_contact_request($user2->id, $user1->id);
4892          $results = api::get_contact_requests_between_users($user1->id, $user2->id);
4893          $results = array_values($results);
4894  
4895          $this->assertCount(1, $results);
4896          $result = $results[0];
4897          $this->assertEquals($request1->id, $result->id);
4898  
4899          $request2 = api::create_contact_request($user1->id, $user2->id);
4900          $results = api::get_contact_requests_between_users($user1->id, $user2->id);
4901          $results = array_values($results);
4902  
4903          $this->assertCount(2, $results);
4904          $actual = [(int) $results[0]->id, (int) $results[1]->id];
4905          $expected = [(int) $request1->id, (int) $request2->id];
4906  
4907          sort($actual);
4908          sort($expected);
4909  
4910          $this->assertEquals($expected, $actual);
4911  
4912          // Request from a different user.
4913          api::create_contact_request($user3->id, $user1->id);
4914  
4915          $results = api::get_contact_requests_between_users($user1->id, $user2->id);
4916          $results = array_values($results);
4917  
4918          $this->assertCount(2, $results);
4919          $actual = [(int) $results[0]->id, (int) $results[1]->id];
4920          $expected = [(int) $request1->id, (int) $request2->id];
4921  
4922          sort($actual);
4923          sort($expected);
4924  
4925          $this->assertEquals($expected, $actual);
4926      }
4927  
4928      /**
4929       * Test the user in conversation check.
4930       */
4931      public function test_is_user_in_conversation() {
4932          $user1 = self::getDataGenerator()->create_user();
4933          $user2 = self::getDataGenerator()->create_user();
4934  
4935          $conversation = api::create_conversation(
4936              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
4937              [
4938                  $user1->id,
4939                  $user2->id
4940              ]
4941          );
4942          $conversationid = $conversation->id;
4943  
4944          $this->assertTrue(api::is_user_in_conversation($user1->id, $conversationid));
4945      }
4946  
4947      /**
4948       * Test the user in conversation check when they are not.
4949       */
4950      public function test_is_user_in_conversation_when_not() {
4951          $user1 = self::getDataGenerator()->create_user();
4952          $user2 = self::getDataGenerator()->create_user();
4953          $user3 = self::getDataGenerator()->create_user();
4954  
4955          $conversation = api::create_conversation(
4956              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
4957              [
4958                  $user1->id,
4959                  $user2->id
4960              ]
4961          );
4962          $conversationid = $conversation->id;
4963  
4964          $this->assertFalse(api::is_user_in_conversation($user3->id, $conversationid));
4965      }
4966  
4967      /**
4968       * Test can create a group conversation.
4969       */
4970      public function test_can_create_group_conversation() {
4971          global $CFG;
4972  
4973          $student = self::getDataGenerator()->create_user();
4974          $teacher = self::getDataGenerator()->create_user();
4975          $course = self::getDataGenerator()->create_course();
4976  
4977          $coursecontext = \context_course::instance($course->id);
4978  
4979          $this->getDataGenerator()->enrol_user($student->id, $course->id);
4980          $this->getDataGenerator()->enrol_user($teacher->id, $course->id, 'editingteacher');
4981  
4982          // Disable messaging.
4983          $CFG->messaging = 0;
4984          $this->assertFalse(api::can_create_group_conversation($student->id, $coursecontext));
4985  
4986          // Re-enable messaging.
4987          $CFG->messaging = 1;
4988  
4989          // Student shouldn't be able to.
4990          $this->assertFalse(api::can_create_group_conversation($student->id, $coursecontext));
4991  
4992          // Teacher should.
4993          $this->assertTrue(api::can_create_group_conversation($teacher->id, $coursecontext));
4994      }
4995  
4996      /**
4997       * Test creating an individual conversation.
4998       */
4999      public function test_create_conversation_individual() {
5000          $user1 = self::getDataGenerator()->create_user();
5001          $user2 = self::getDataGenerator()->create_user();
5002  
5003          $conversation = api::create_conversation(
5004              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
5005              [
5006                  $user1->id,
5007                  $user2->id
5008              ],
5009              'A conversation name'
5010          );
5011  
5012          $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $conversation->type);
5013          $this->assertEquals('A conversation name', $conversation->name);
5014          $this->assertEquals(helper::get_conversation_hash([$user1->id, $user2->id]), $conversation->convhash);
5015  
5016          $this->assertCount(2, $conversation->members);
5017  
5018          $member1 = array_shift($conversation->members);
5019          $member2 = array_shift($conversation->members);
5020  
5021          $this->assertEquals($user1->id, $member1->userid);
5022          $this->assertEquals($conversation->id, $member1->conversationid);
5023  
5024          $this->assertEquals($user2->id, $member2->userid);
5025          $this->assertEquals($conversation->id, $member2->conversationid);
5026      }
5027  
5028      /**
5029       * Test creating a group conversation.
5030       */
5031      public function test_create_conversation_group() {
5032          $user1 = self::getDataGenerator()->create_user();
5033          $user2 = self::getDataGenerator()->create_user();
5034          $user3 = self::getDataGenerator()->create_user();
5035  
5036          $conversation = api::create_conversation(
5037              api::MESSAGE_CONVERSATION_TYPE_GROUP,
5038              [
5039                  $user1->id,
5040                  $user2->id,
5041                  $user3->id
5042              ],
5043              'A conversation name'
5044          );
5045  
5046          $this->assertEquals(api::MESSAGE_CONVERSATION_TYPE_GROUP, $conversation->type);
5047          $this->assertEquals('A conversation name', $conversation->name);
5048          $this->assertNull($conversation->convhash);
5049  
5050          $this->assertCount(3, $conversation->members);
5051  
5052          $member1 = array_shift($conversation->members);
5053          $member2 = array_shift($conversation->members);
5054          $member3 = array_shift($conversation->members);
5055  
5056          $this->assertEquals($user1->id, $member1->userid);
5057          $this->assertEquals($conversation->id, $member1->conversationid);
5058  
5059          $this->assertEquals($user2->id, $member2->userid);
5060          $this->assertEquals($conversation->id, $member2->conversationid);
5061  
5062          $this->assertEquals($user3->id, $member3->userid);
5063          $this->assertEquals($conversation->id, $member3->conversationid);
5064      }
5065  
5066      /**
5067       * Test creating an invalid conversation.
5068       */
5069      public function test_create_conversation_invalid() {
5070          $this->expectException('moodle_exception');
5071          api::create_conversation(3, [1, 2, 3]);
5072      }
5073  
5074      /**
5075       * Test creating an individual conversation with too many members.
5076       */
5077      public function test_create_conversation_individual_too_many_members() {
5078          $this->expectException('moodle_exception');
5079          api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, [1, 2, 3]);
5080      }
5081  
5082      /**
5083       * Test create message conversation with area.
5084       */
5085      public function test_create_conversation_with_area() {
5086          $contextid = 111;
5087          $itemid = 222;
5088          $name = 'Name of conversation';
5089          $conversation = api::create_conversation(
5090              api::MESSAGE_CONVERSATION_TYPE_GROUP,
5091              [],
5092              $name,
5093              api::MESSAGE_CONVERSATION_DISABLED,
5094              'core_group',
5095              'groups',
5096              $itemid,
5097              $contextid
5098          );
5099  
5100          $this->assertEquals(api::MESSAGE_CONVERSATION_DISABLED, $conversation->enabled);
5101          $this->assertEquals('core_group', $conversation->component);
5102          $this->assertEquals('groups', $conversation->itemtype);
5103          $this->assertEquals($itemid, $conversation->itemid);
5104          $this->assertEquals($contextid, $conversation->contextid);
5105      }
5106  
5107      /**
5108       * Test get_conversation_by_area.
5109       */
5110      public function test_get_conversation_by_area() {
5111          $contextid = 111;
5112          $itemid = 222;
5113          $name = 'Name of conversation';
5114          $createconversation = api::create_conversation(
5115              api::MESSAGE_CONVERSATION_TYPE_GROUP,
5116              [],
5117              $name,
5118              api::MESSAGE_CONVERSATION_DISABLED,
5119              'core_group',
5120              'groups',
5121              $itemid,
5122              $contextid
5123          );
5124          $conversation = api::get_conversation_by_area('core_group', 'groups', $itemid, $contextid);
5125  
5126          $this->assertEquals($createconversation->id, $conversation->id);
5127          $this->assertEquals(api::MESSAGE_CONVERSATION_DISABLED, $conversation->enabled);
5128          $this->assertEquals('core_group', $conversation->component);
5129          $this->assertEquals('groups', $conversation->itemtype);
5130          $this->assertEquals($itemid, $conversation->itemid);
5131          $this->assertEquals($contextid, $conversation->contextid);
5132      }
5133  
5134      /**
5135       * Test enable_conversation.
5136       */
5137      public function test_enable_conversation() {
5138          global $DB;
5139  
5140          $name = 'Name of conversation';
5141  
5142          $conversation = api::create_conversation(
5143              api::MESSAGE_CONVERSATION_TYPE_GROUP,
5144              [],
5145              $name,
5146              api::MESSAGE_CONVERSATION_DISABLED
5147          );
5148  
5149          $this->assertEquals(api::MESSAGE_CONVERSATION_DISABLED, $conversation->enabled);
5150          api::enable_conversation($conversation->id);
5151          $conversationenabled = $DB->get_field('message_conversations', 'enabled', ['id' => $conversation->id]);
5152          $this->assertEquals(api::MESSAGE_CONVERSATION_ENABLED, $conversationenabled);
5153      }
5154  
5155      /**
5156       * Test disable_conversation.
5157       */
5158      public function test_disable_conversation() {
5159          global $DB;
5160  
5161          $name = 'Name of conversation';
5162  
5163          $conversation = api::create_conversation(
5164              api::MESSAGE_CONVERSATION_TYPE_GROUP,
5165              [],
5166              $name,
5167              api::MESSAGE_CONVERSATION_ENABLED
5168          );
5169  
5170          $this->assertEquals(api::MESSAGE_CONVERSATION_ENABLED, $conversation->enabled);
5171          api::disable_conversation($conversation->id);
5172          $conversationenabled = $DB->get_field('message_conversations', 'enabled', ['id' => $conversation->id]);
5173          $this->assertEquals(api::MESSAGE_CONVERSATION_DISABLED, $conversationenabled);
5174      }
5175  
5176      /**
5177       * Test update_conversation_name.
5178       */
5179      public function test_update_conversation_name() {
5180          global $DB;
5181  
5182          $conversation = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_GROUP, []);
5183  
5184          $newname = 'New name of conversation';
5185          api::update_conversation_name($conversation->id, $newname);
5186  
5187          $this->assertEquals(
5188                  $newname,
5189                  $DB->get_field('message_conversations', 'name', ['id' => $conversation->id])
5190          );
5191      }
5192  
5193  
5194      /**
5195       * Test an empty array returned when no args given.
5196       */
5197      public function test_get_individual_conversations_between_users_no_user_sets() {
5198          $this->assertEmpty(\core_message\api::get_individual_conversations_between_users([]));
5199          $this->assertDebuggingCalled();
5200      }
5201  
5202      /**
5203       * Test a conversation is not returned if there is none.
5204       */
5205      public function test_get_individual_conversations_between_users_no_conversation() {
5206          $generator = $this->getDataGenerator();
5207          $user1 = $generator->create_user();
5208          $user2 = $generator->create_user();
5209  
5210          $this->assertEquals(
5211              [null],
5212              \core_message\api::get_individual_conversations_between_users([[$user1->id, $user2->id]])
5213          );
5214          $this->assertDebuggingCalled();
5215      }
5216  
5217      /**
5218       * Test the result set includes null if there is no conversation between users.
5219       */
5220      public function test_get_individual_conversations_between_users_partial_conversations() {
5221          $generator = $this->getDataGenerator();
5222          $user1 = $generator->create_user();
5223          $user2 = $generator->create_user();
5224          $user3 = $generator->create_user();
5225          $type = \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL;
5226  
5227          $conversation1 = \core_message\api::create_conversation($type, [$user1->id, $user2->id]);
5228          $conversation2 = \core_message\api::create_conversation($type, [$user1->id, $user3->id]);
5229  
5230          $results = \core_message\api::get_individual_conversations_between_users([
5231              [$user1->id, $user2->id],
5232              [$user2->id, $user3->id],
5233              [$user1->id, $user3->id]
5234          ]);
5235          $this->assertDebuggingCalled();
5236  
5237          $result = array_map(function($result) {
5238              if ($result) {
5239                  return $result->id;
5240              } else {
5241                  return $result;
5242              }
5243          }, $results);
5244  
5245          $this->assertEquals(
5246              [$conversation1->id, null, $conversation2->id],
5247              $result
5248          );
5249      }
5250  
5251      /**
5252       * Test all conversations are returned if each set has a conversation.
5253       */
5254      public function test_get_individual_conversations_between_users_all_conversations() {
5255          $generator = $this->getDataGenerator();
5256          $user1 = $generator->create_user();
5257          $user2 = $generator->create_user();
5258          $user3 = $generator->create_user();
5259          $type = \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL;
5260  
5261          $conversation1 = \core_message\api::create_conversation($type, [$user1->id, $user2->id]);
5262          $conversation2 = \core_message\api::create_conversation($type, [$user2->id, $user3->id]);
5263          $conversation3 = \core_message\api::create_conversation($type, [$user1->id, $user3->id]);
5264  
5265          $results = \core_message\api::get_individual_conversations_between_users([
5266              [$user1->id, $user2->id],
5267              [$user2->id, $user3->id],
5268              [$user1->id, $user3->id]
5269          ]);
5270          $this->assertDebuggingCalled();
5271  
5272          $result = array_map(function($result) {
5273              if ($result) {
5274                  return $result->id;
5275              } else {
5276                  return $result;
5277              }
5278          }, $results);
5279  
5280          $this->assertEquals(
5281              [$conversation1->id, $conversation2->id, $conversation3->id],
5282              $result
5283          );
5284      }
5285  
5286      /**
5287       * Test that the results are ordered to match the order of the parameters.
5288       */
5289      public function test_get_individual_conversations_between_users_ordering() {
5290          $generator = $this->getDataGenerator();
5291          $user1 = $generator->create_user();
5292          $user2 = $generator->create_user();
5293          $user3 = $generator->create_user();
5294          $type = \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL;
5295  
5296          $conversation1 = \core_message\api::create_conversation($type, [$user1->id, $user2->id]);
5297          $conversation2 = \core_message\api::create_conversation($type, [$user2->id, $user3->id]);
5298          $conversation3 = \core_message\api::create_conversation($type, [$user1->id, $user3->id]);
5299  
5300          $results = \core_message\api::get_individual_conversations_between_users([
5301              [$user1->id, $user2->id],
5302              [$user2->id, $user3->id],
5303              [$user1->id, $user3->id]
5304          ]);
5305          $this->assertDebuggingCalled();
5306  
5307          $result = array_map(function($result) {
5308              if ($result) {
5309                  return $result->id;
5310              } else {
5311                  return $result;
5312              }
5313          }, $results);
5314  
5315          $this->assertEquals(
5316              [$conversation1->id, $conversation2->id, $conversation3->id],
5317              $result
5318          );
5319  
5320          $results = \core_message\api::get_individual_conversations_between_users([
5321              [$user2->id, $user3->id],
5322              [$user1->id, $user2->id],
5323              [$user1->id, $user3->id]
5324          ]);
5325          $this->assertDebuggingCalled();
5326  
5327          $result = array_map(function($result) {
5328              if ($result) {
5329                  return $result->id;
5330              } else {
5331                  return $result;
5332              }
5333          }, $results);
5334  
5335          $this->assertEquals(
5336              [$conversation2->id, $conversation1->id, $conversation3->id],
5337              $result
5338          );
5339      }
5340  
5341      /**
5342       * Test returning members in a conversation with no contact requests.
5343       */
5344      public function test_get_conversation_members() {
5345          $lastaccess = new \stdClass();
5346          $lastaccess->lastaccess = time();
5347  
5348          $user1 = self::getDataGenerator()->create_user($lastaccess);
5349          $user2 = self::getDataGenerator()->create_user();
5350          $user3 = self::getDataGenerator()->create_user();
5351  
5352          // This user will not be in the conversation, but a contact request will exist for them.
5353          $user4 = self::getDataGenerator()->create_user();
5354  
5355          // Add some contact requests.
5356          api::create_contact_request($user1->id, $user3->id);
5357          api::create_contact_request($user1->id, $user4->id);
5358          api::create_contact_request($user2->id, $user3->id);
5359  
5360          // User 1 and 2 are already contacts.
5361          api::add_contact($user1->id, $user2->id);
5362  
5363          // User 1 has blocked user 3.
5364          api::block_user($user1->id, $user3->id);
5365          $conversation = api::create_conversation(
5366              api::MESSAGE_CONVERSATION_TYPE_GROUP,
5367              [
5368                  $user1->id,
5369                  $user2->id,
5370                  $user3->id
5371              ]
5372          );
5373          $conversationid = $conversation->id;
5374          $members = api::get_conversation_members($user1->id, $conversationid, false);
5375  
5376          // Sort them by id.
5377          ksort($members);
5378          $this->assertCount(3, $members);
5379          $member1 = array_shift($members);
5380          $member2 = array_shift($members);
5381          $member3 = array_shift($members);
5382  
5383          // Confirm the standard fields are OK.
5384          $this->assertEquals($user1->id, $member1->id);
5385          $this->assertEquals(fullname($user1), $member1->fullname);
5386          $this->assertEquals(true, $member1->isonline);
5387          $this->assertEquals(true, $member1->showonlinestatus);
5388          $this->assertEquals(false, $member1->iscontact);
5389          $this->assertEquals(false, $member1->isblocked);
5390          $this->assertObjectHasAttribute('contactrequests', $member1);
5391          $this->assertEmpty($member1->contactrequests);
5392  
5393          $this->assertEquals($user2->id, $member2->id);
5394          $this->assertEquals(fullname($user2), $member2->fullname);
5395          $this->assertEquals(false, $member2->isonline);
5396          $this->assertEquals(true, $member2->showonlinestatus);
5397          $this->assertEquals(true, $member2->iscontact);
5398          $this->assertEquals(false, $member2->isblocked);
5399          $this->assertObjectHasAttribute('contactrequests', $member2);
5400          $this->assertEmpty($member2->contactrequests);
5401  
5402          $this->assertEquals($user3->id, $member3->id);
5403          $this->assertEquals(fullname($user3), $member3->fullname);
5404          $this->assertEquals(false, $member3->isonline);
5405          $this->assertEquals(true, $member3->showonlinestatus);
5406          $this->assertEquals(false, $member3->iscontact);
5407          $this->assertEquals(true, $member3->isblocked);
5408          $this->assertObjectHasAttribute('contactrequests', $member3);
5409          $this->assertEmpty($member3->contactrequests);
5410      }
5411  
5412      /**
5413       * Test returning members in a conversation with contact requests.
5414       */
5415      public function test_get_conversation_members_with_contact_requests() {
5416          $lastaccess = new \stdClass();
5417          $lastaccess->lastaccess = time();
5418  
5419          $user1 = self::getDataGenerator()->create_user($lastaccess);
5420          $user2 = self::getDataGenerator()->create_user();
5421          $user3 = self::getDataGenerator()->create_user();
5422  
5423          // This user will not be in the conversation, but a contact request will exist for them.
5424          $user4 = self::getDataGenerator()->create_user();
5425          // Add some contact requests.
5426          api::create_contact_request($user1->id, $user2->id);
5427          api::create_contact_request($user1->id, $user3->id);
5428          api::create_contact_request($user1->id, $user4->id);
5429          api::create_contact_request($user2->id, $user3->id);
5430  
5431          // User 1 and 2 are already contacts.
5432          api::add_contact($user1->id, $user2->id);
5433          // User 1 has blocked user 3.
5434          api::block_user($user1->id, $user3->id);
5435  
5436          $conversation = api::create_conversation(
5437              api::MESSAGE_CONVERSATION_TYPE_GROUP,
5438              [
5439                  $user1->id,
5440                  $user2->id,
5441                  $user3->id
5442              ]
5443          );
5444          $conversationid = $conversation->id;
5445  
5446          $members = api::get_conversation_members($user1->id, $conversationid, true);
5447  
5448          // Sort them by id.
5449          ksort($members);
5450  
5451          $this->assertCount(3, $members);
5452  
5453          $member1 = array_shift($members);
5454          $member2 = array_shift($members);
5455          $member3 = array_shift($members);
5456  
5457          // Confirm the standard fields are OK.
5458          $this->assertEquals($user1->id, $member1->id);
5459          $this->assertEquals(fullname($user1), $member1->fullname);
5460          $this->assertEquals(true, $member1->isonline);
5461          $this->assertEquals(true, $member1->showonlinestatus);
5462          $this->assertEquals(false, $member1->iscontact);
5463          $this->assertEquals(false, $member1->isblocked);
5464          $this->assertCount(2, $member1->contactrequests);
5465  
5466          $this->assertEquals($user2->id, $member2->id);
5467          $this->assertEquals(fullname($user2), $member2->fullname);
5468          $this->assertEquals(false, $member2->isonline);
5469          $this->assertEquals(true, $member2->showonlinestatus);
5470          $this->assertEquals(true, $member2->iscontact);
5471          $this->assertEquals(false, $member2->isblocked);
5472          $this->assertCount(1, $member2->contactrequests);
5473  
5474          $this->assertEquals($user3->id, $member3->id);
5475          $this->assertEquals(fullname($user3), $member3->fullname);
5476          $this->assertEquals(false, $member3->isonline);
5477          $this->assertEquals(true, $member3->showonlinestatus);
5478          $this->assertEquals(false, $member3->iscontact);
5479          $this->assertEquals(true, $member3->isblocked);
5480          $this->assertCount(1, $member3->contactrequests);
5481  
5482          // Confirm the contact requests are OK.
5483          $request1 = array_shift($member1->contactrequests);
5484          $request2 = array_shift($member1->contactrequests);
5485  
5486          $this->assertEquals($user1->id, $request1->userid);
5487          $this->assertEquals($user2->id, $request1->requesteduserid);
5488  
5489          $this->assertEquals($user1->id, $request2->userid);
5490          $this->assertEquals($user3->id, $request2->requesteduserid);
5491  
5492          $request1 = array_shift($member2->contactrequests);
5493  
5494          $this->assertEquals($user1->id, $request1->userid);
5495          $this->assertEquals($user2->id, $request1->requesteduserid);
5496  
5497          $request1 = array_shift($member3->contactrequests);
5498  
5499          $this->assertEquals($user1->id, $request1->userid);
5500          $this->assertEquals($user3->id, $request1->requesteduserid);
5501      }
5502  
5503      /**
5504       * Test returning members of a self conversation.
5505       */
5506      public function test_get_conversation_members_with_self_conversation() {
5507          $lastaccess = new \stdClass();
5508          $lastaccess->lastaccess = time();
5509  
5510          $user1 = self::getDataGenerator()->create_user($lastaccess);
5511  
5512          $selfconversation = api::get_self_conversation($user1->id);
5513          testhelper::send_fake_message_to_conversation($user1, $selfconversation->id, 'This is a self-message!');
5514  
5515          // Get the members for the self-conversation.
5516          $members = api::get_conversation_members($user1->id, $selfconversation->id);
5517          $this->assertCount(1, $members);
5518  
5519          $member1 = array_shift($members);
5520  
5521          // Confirm the standard fields are OK.
5522          $this->assertEquals($user1->id, $member1->id);
5523          $this->assertEquals(fullname($user1), $member1->fullname);
5524          $this->assertEquals(true, $member1->isonline);
5525          $this->assertEquals(true, $member1->showonlinestatus);
5526          $this->assertEquals(false, $member1->iscontact);
5527          $this->assertEquals(false, $member1->isblocked);
5528      }
5529  
5530      /**
5531       * Test verifying that messages can be sent to existing individual conversations.
5532       */
5533      public function test_send_message_to_conversation_individual_conversation() {
5534          // Get a bunch of conversations, some group, some individual and in different states.
5535          list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
5536              $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
5537  
5538          // Enrol the users into the same course so the privacy checks will pass using default (contact+course members) setting.
5539          $course = $this->getDataGenerator()->create_course();
5540          $this->getDataGenerator()->enrol_user($user1->id, $course->id);
5541          $this->getDataGenerator()->enrol_user($user2->id, $course->id);
5542          $this->getDataGenerator()->enrol_user($user3->id, $course->id);
5543          $this->getDataGenerator()->enrol_user($user4->id, $course->id);
5544  
5545          // Redirect messages.
5546          // This marks messages as read, but we can still observe and verify the number of conversation recipients,
5547          // based on the message_viewed events generated as part of marking the message as read for each user.
5548          $this->preventResetByRollback();
5549          $sink = $this->redirectMessages();
5550  
5551          // Send a message to an individual conversation.
5552          $sink = $this->redirectEvents();
5553          $messagessink = $this->redirectMessages();
5554          $message1 = api::send_message_to_conversation($user1->id, $ic1->id, 'this is a message', FORMAT_MOODLE);
5555          $events = $sink->get_events();
5556          $messages = $messagessink->get_messages();
5557          // Test customdata.
5558          $customdata = json_decode($messages[0]->customdata);
5559          $this->assertObjectHasAttribute('notificationiconurl', $customdata);
5560          $this->assertObjectHasAttribute('actionbuttons', $customdata);
5561          $this->assertCount(1, (array) $customdata->actionbuttons);
5562          $this->assertObjectHasAttribute('placeholders', $customdata);
5563          $this->assertCount(1, (array) $customdata->placeholders);
5564  
5565          // Verify the message returned.
5566          $this->assertInstanceOf(\stdClass::class, $message1);
5567          $this->assertObjectHasAttribute('id', $message1);
5568          $this->assertEquals($user1->id, $message1->useridfrom);
5569          $this->assertEquals('this is a message', $message1->text);
5570          $this->assertObjectHasAttribute('timecreated', $message1);
5571  
5572          // Verify events. Note: the event is a message read event because of an if (PHPUNIT) conditional within message_send(),
5573          // however, we can still determine the number and ids of any recipients this way.
5574          $this->assertCount(1, $events);
5575          $userids = array_column($events, 'userid');
5576          $this->assertNotContainsEquals($user1->id, $userids);
5577          $this->assertContainsEquals($user2->id, $userids);
5578      }
5579  
5580      /**
5581       * Test verifying that messages can be sent to existing group conversations.
5582       */
5583      public function test_send_message_to_conversation_group_conversation() {
5584          // Get a bunch of conversations, some group, some individual and in different states.
5585          list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
5586              $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
5587  
5588          // Enrol the users into the same course so the privacy checks will pass using default (contact+course members) setting.
5589          $course = $this->getDataGenerator()->create_course();
5590          $this->getDataGenerator()->enrol_user($user1->id, $course->id);
5591          $this->getDataGenerator()->enrol_user($user2->id, $course->id);
5592          $this->getDataGenerator()->enrol_user($user3->id, $course->id);
5593          $this->getDataGenerator()->enrol_user($user4->id, $course->id);
5594  
5595          // Redirect messages.
5596          // This marks messages as read, but we can still observe and verify the number of conversation recipients,
5597          // based on the message_viewed events generated as part of marking the message as read for each user.
5598          $this->preventResetByRollback();
5599          $sink = $this->redirectMessages();
5600  
5601          // Send a message to a group conversation.
5602          $sink = $this->redirectEvents();
5603          $messagessink = $this->redirectMessages();
5604          $message1 = api::send_message_to_conversation($user1->id, $gc2->id, 'message to the group', FORMAT_MOODLE);
5605          $events = $sink->get_events();
5606          $messages = $messagessink->get_messages();
5607          // Verify the message returned.
5608          $this->assertInstanceOf(\stdClass::class, $message1);
5609          $this->assertObjectHasAttribute('id', $message1);
5610          $this->assertEquals($user1->id, $message1->useridfrom);
5611          $this->assertEquals('message to the group', $message1->text);
5612          $this->assertObjectHasAttribute('timecreated', $message1);
5613          // Test customdata.
5614          $customdata = json_decode($messages[0]->customdata);
5615          $this->assertObjectHasAttribute('actionbuttons', $customdata);
5616          $this->assertCount(1, (array) $customdata->actionbuttons);
5617          $this->assertObjectHasAttribute('placeholders', $customdata);
5618          $this->assertCount(1, (array) $customdata->placeholders);
5619          $this->assertObjectNotHasAttribute('notificationiconurl', $customdata);    // No group image means no image.
5620  
5621          // Verify events. Note: the event is a message read event because of an if (PHPUNIT) conditional within message_send(),
5622          // however, we can still determine the number and ids of any recipients this way.
5623          $this->assertCount(2, $events);
5624          $userids = array_column($events, 'userid');
5625          $this->assertNotContainsEquals($user1->id, $userids);
5626          $this->assertContainsEquals($user3->id, $userids);
5627          $this->assertContainsEquals($user4->id, $userids);
5628      }
5629  
5630      /**
5631       * Test verifying that messages can be sent to existing linked group conversations.
5632       */
5633      public function test_send_message_to_conversation_linked_group_conversation() {
5634          global $CFG, $PAGE;
5635  
5636          // Create some users.
5637          $user1 = self::getDataGenerator()->create_user();
5638          $user2 = self::getDataGenerator()->create_user();
5639          $user3 = self::getDataGenerator()->create_user();
5640  
5641          $course = $this->getDataGenerator()->create_course();
5642  
5643          // Create a group with a linked conversation and a valid image.
5644          $this->setAdminUser();
5645          $this->getDataGenerator()->enrol_user($user1->id, $course->id);
5646          $this->getDataGenerator()->enrol_user($user2->id, $course->id);
5647          $this->getDataGenerator()->enrol_user($user3->id, $course->id);
5648          $group = $this->getDataGenerator()->create_group([
5649              'courseid' => $course->id,
5650              'enablemessaging' => 1,
5651              'picturepath' => $CFG->dirroot . '/lib/tests/fixtures/gd-logo.png'
5652          ]);
5653  
5654          // Add users to group.
5655          $this->getDataGenerator()->create_group_member(array('groupid' => $group->id, 'userid' => $user1->id));
5656          $this->getDataGenerator()->create_group_member(array('groupid' => $group->id, 'userid' => $user2->id));
5657  
5658          // Verify the group with the image works as expected.
5659          $conversations = api::get_conversations($user1->id);
5660          $this->assertEquals(2, $conversations[0]->membercount);
5661          $this->assertEquals($course->shortname, $conversations[0]->subname);
5662          $groupimageurl = get_group_picture_url($group, $group->courseid, true);
5663          $this->assertEquals($groupimageurl, $conversations[0]->imageurl);
5664  
5665          // Redirect messages.
5666          // This marks messages as read, but we can still observe and verify the number of conversation recipients,
5667          // based on the message_viewed events generated as part of marking the message as read for each user.
5668          $this->preventResetByRollback();
5669          $sink = $this->redirectMessages();
5670  
5671          // Send a message to a group conversation.
5672          $messagessink = $this->redirectMessages();
5673          $message1 = api::send_message_to_conversation($user1->id, $conversations[0]->id,
5674              'message to the group', FORMAT_MOODLE);
5675          $messages = $messagessink->get_messages();
5676          // Verify the message returned.
5677          $this->assertInstanceOf(\stdClass::class, $message1);
5678          $this->assertObjectHasAttribute('id', $message1);
5679          $this->assertEquals($user1->id, $message1->useridfrom);
5680          $this->assertEquals('message to the group', $message1->text);
5681          $this->assertObjectHasAttribute('timecreated', $message1);
5682          // Test customdata.
5683          $customdata = json_decode($messages[0]->customdata);
5684          $this->assertObjectHasAttribute('notificationiconurl', $customdata);
5685          $this->assertObjectHasAttribute('notificationsendericonurl', $customdata);
5686          $this->assertEquals($groupimageurl, $customdata->notificationiconurl);
5687          $this->assertEquals($group->name, $customdata->conversationname);
5688          $userpicture = new \user_picture($user1);
5689          $userpicture->size = 1; // Use f1 size.
5690          $this->assertEquals($userpicture->get_url($PAGE)->out(false), $customdata->notificationsendericonurl);
5691      }
5692  
5693      /**
5694       * Test verifying that messages cannot be sent to conversations that don't exist.
5695       */
5696      public function test_send_message_to_conversation_non_existent_conversation() {
5697          // Get a bunch of conversations, some group, some individual and in different states.
5698          list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
5699              $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
5700  
5701          $this->expectException(\moodle_exception::class);
5702          api::send_message_to_conversation($user1->id, 0, 'test', FORMAT_MOODLE);
5703      }
5704  
5705      /**
5706       * Test verifying that messages cannot be sent to conversations by users who are not members.
5707       */
5708      public function test_send_message_to_conversation_non_member() {
5709          // Get a bunch of conversations, some group, some individual and in different states.
5710          list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
5711              $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
5712  
5713          // Enrol the users into the same course so the privacy checks will pass using default (contact+course members) setting.
5714          $course = $this->getDataGenerator()->create_course();
5715          $this->getDataGenerator()->enrol_user($user1->id, $course->id);
5716          $this->getDataGenerator()->enrol_user($user2->id, $course->id);
5717          $this->getDataGenerator()->enrol_user($user3->id, $course->id);
5718          $this->getDataGenerator()->enrol_user($user4->id, $course->id);
5719  
5720          $this->expectException(\moodle_exception::class);
5721          api::send_message_to_conversation($user3->id, $ic1->id, 'test', FORMAT_MOODLE);
5722      }
5723  
5724      /**
5725       * Test verifying that messages cannot be sent to conversations by users who are not members.
5726       */
5727      public function test_send_message_to_conversation_blocked_user() {
5728          // Get a bunch of conversations, some group, some individual and in different states.
5729          list($user1, $user2, $user3, $user4, $ic1, $ic2, $ic3,
5730              $gc1, $gc2, $gc3, $gc4, $gc5, $gc6) = $this->create_conversation_test_data();
5731  
5732          // Enrol the users into the same course so the privacy checks will pass using default (contact+course members) setting.
5733          $course = $this->getDataGenerator()->create_course();
5734          $this->getDataGenerator()->enrol_user($user1->id, $course->id);
5735          $this->getDataGenerator()->enrol_user($user2->id, $course->id);
5736          $this->getDataGenerator()->enrol_user($user3->id, $course->id);
5737          $this->getDataGenerator()->enrol_user($user4->id, $course->id);
5738  
5739          // User 1 blocks user 2.
5740          api::block_user($user1->id, $user2->id);
5741  
5742          // Verify that a message can be sent to any group conversation in which user1 and user2 are members.
5743          $this->assertNotEmpty(api::send_message_to_conversation($user1->id, $gc2->id, 'Hey guys', FORMAT_PLAIN));
5744  
5745          // User 2 cannot send a message to the conversation with user 1.
5746          $this->expectException(\moodle_exception::class);
5747          api::send_message_to_conversation($user2->id, $ic1->id, 'test', FORMAT_MOODLE);
5748      }
5749  
5750      /**
5751       * Test the get_conversation() function with a muted conversation.
5752       */
5753      public function test_get_conversation_with_muted_conversation() {
5754          $this->resetAfterTest();
5755  
5756          $user1 = self::getDataGenerator()->create_user();
5757          $user2 = self::getDataGenerator()->create_user();
5758  
5759          $this->setUser($user1);
5760  
5761          $conversation = api::create_conversation(api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
5762              [$user1->id, $user2->id]);
5763  
5764          $conversation = api::get_conversation($user1->id, $conversation->id);
5765  
5766          $this->assertFalse($conversation->ismuted);
5767  
5768          // Now, mute the conversation.
5769          api::mute_conversation($user1->id, $conversation->id);
5770  
5771          $conversation = api::get_conversation($user1->id, $conversation->id);
5772  
5773          $this->assertTrue($conversation->ismuted);
5774      }
5775  
5776      /**
5777       * Data provider for test_get_conversation_counts().
5778       */
5779      public function get_conversation_counts_test_cases() {
5780          $typeindividual = api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL;
5781          $typegroup = api::MESSAGE_CONVERSATION_TYPE_GROUP;
5782          $typeself = api::MESSAGE_CONVERSATION_TYPE_SELF;
5783          list($user1, $user2, $user3, $user4, $user5, $user6, $user7, $user8) = [0, 1, 2, 3, 4, 5, 6, 7];
5784          $conversations = [
5785              [
5786                  'type' => $typeindividual,
5787                  'users' => [$user1, $user2],
5788                  'messages' => [$user1, $user2, $user2],
5789                  'favourites' => [$user1],
5790                  'enabled' => null // Individual conversations cannot be disabled.
5791              ],
5792              [
5793                  'type' => $typeindividual,
5794                  'users' => [$user1, $user3],
5795                  'messages' => [$user1, $user3, $user1],
5796                  'favourites' => [],
5797                  'enabled' => null // Individual conversations cannot be disabled.
5798              ],
5799              [
5800                  'type' => $typegroup,
5801                  'users' => [$user1, $user2, $user3, $user4],
5802                  'messages' => [$user1, $user2, $user3, $user4],
5803                  'favourites' => [],
5804                  'enabled' => true
5805              ],
5806              [
5807                  'type' => $typegroup,
5808                  'users' => [$user2, $user3, $user4],
5809                  'messages' => [$user2, $user3, $user4],
5810                  'favourites' => [],
5811                  'enabled' => true
5812              ],
5813              [
5814                  'type' => $typegroup,
5815                  'users' => [$user6, $user7],
5816                  'messages' => [$user6, $user7, $user7],
5817                  'favourites' => [$user6],
5818                  'enabled' => false
5819              ],
5820              [
5821                  'type' => $typeself,
5822                  'users' => [$user8],
5823                  'messages' => [$user8],
5824                  'favourites' => [],
5825                  'enabled' => null // Self-conversations cannot be disabled.
5826              ],
5827          ];
5828  
5829          return [
5830              'No conversations' => [
5831                  'conversationConfigs' => $conversations,
5832                  'deletemessagesuser' => null,
5833                  'deletemessages' => [],
5834                  'arguments' => [$user5],
5835                  'expectedcounts' => ['favourites' => 1, 'types' => [
5836                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
5837                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 0,
5838                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5839                  ]],
5840                  'expectedunreadcounts' => ['favourites' => 0, 'types' => [
5841                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
5842                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 0,
5843                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5844                  ]],
5845                  'deletedusers' => []
5846              ],
5847              'No individual conversations, 2 group conversations' => [
5848                  'conversationConfigs' => $conversations,
5849                  'deletemessagesuser' => null,
5850                  'deletemessages' => [],
5851                  'arguments' => [$user4],
5852                  'expectedcounts' => ['favourites' => 1, 'types' => [
5853                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
5854                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 2,
5855                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5856                  ]],
5857                  'expectedunreadcounts' => ['favourites' => 0, 'types' => [
5858                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
5859                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 2,
5860                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5861                  ]],
5862                  'deletedusers' => []
5863              ],
5864              '2 individual conversations (one favourited), 1 group conversation' => [
5865                  'conversationConfigs' => $conversations,
5866                  'deletemessagesuser' => null,
5867                  'deletemessages' => [],
5868                  'arguments' => [$user1],
5869                  'expectedcounts' => ['favourites' => 2, 'types' => [
5870                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
5871                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 1,
5872                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5873                  ]],
5874                  'expectedunreadcounts' => ['favourites' => 1, 'types' => [
5875                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
5876                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 1,
5877                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5878                  ]],
5879                  'deletedusers' => []
5880              ],
5881              '1 individual conversation, 2 group conversations' => [
5882                  'conversationConfigs' => $conversations,
5883                  'deletemessagesuser' => null,
5884                  'deletemessages' => [],
5885                  'arguments' => [$user2],
5886                  'expectedcounts' => ['favourites' => 1, 'types' => [
5887                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
5888                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 2,
5889                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5890                  ]],
5891                  'expectedunreadcounts' => ['favourites' => 0, 'types' => [
5892                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
5893                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 2,
5894                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5895                  ]],
5896                  'deletedusers' => []
5897              ],
5898              '2 group conversations only' => [
5899                  'conversationConfigs' => $conversations,
5900                  'deletemessagesuser' => null,
5901                  'deletemessages' => [],
5902                  'arguments' => [$user4],
5903                  'expectedcounts' => ['favourites' => 1, 'types' => [
5904                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
5905                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 2,
5906                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5907                  ]],
5908                  'expectedunreadcounts' => ['favourites' => 0, 'types' => [
5909                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
5910                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 2,
5911                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5912                  ]],
5913                  'deletedusers' => []
5914              ],
5915              'All conversation types, delete a message from individual favourited, messages remaining' => [
5916                  'conversationConfigs' => $conversations,
5917                  'deletemessagesuser' => $user1,
5918                  'deletemessages' => [0],
5919                  'arguments' => [$user1],
5920                  'expectedcounts' => ['favourites' => 2, 'types' => [
5921                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
5922                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 1,
5923                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5924                  ]],
5925                  'expectedunreadcounts' => ['favourites' => 1, 'types' => [
5926                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
5927                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 1,
5928                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5929                  ]],
5930                  'deletedusers' => []
5931              ],
5932              'All conversation types, delete a message from individual non-favourited, messages remaining' => [
5933                  'conversationConfigs' => $conversations,
5934                  'deletemessagesuser' => $user1,
5935                  'deletemessages' => [3],
5936                  'arguments' => [$user1],
5937                  'expectedcounts' => ['favourites' => 2, 'types' => [
5938                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
5939                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 1,
5940                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5941                  ]],
5942                  'expectedunreadcounts' => ['favourites' => 1, 'types' => [
5943                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
5944                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 1,
5945                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5946                  ]],
5947                  'deletedusers' => []
5948              ],
5949              'All conversation types, delete all messages from individual favourited, no messages remaining' => [
5950                  'conversationConfigs' => $conversations,
5951                  'deletemessagesuser' => $user1,
5952                  'deletemessages' => [0, 1, 2],
5953                  'arguments' => [$user1],
5954                  'expectedcounts' => ['favourites' => 1, 'types' => [
5955                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
5956                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 1,
5957                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5958                  ]],
5959                  'expectedunreadcounts' => ['favourites' => 0, 'types' => [
5960                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
5961                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 1,
5962                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5963                  ]],
5964                  'deletedusers' => []
5965              ],
5966              'All conversation types, delete all messages from individual non-favourited, no messages remaining' => [
5967                  'conversationConfigs' => $conversations,
5968                  'deletemessagesuser' => $user1,
5969                  'deletemessages' => [3, 4, 5],
5970                  'arguments' => [$user1],
5971                  'expectedcounts' => ['favourites' => 2, 'types' => [
5972                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
5973                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 1,
5974                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5975                  ]],
5976                  'expectedunreadcounts' => ['favourites' => 1, 'types' => [
5977                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
5978                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 1,
5979                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5980                  ]],
5981                  'deletedusers' => []
5982              ],
5983              'All conversation types, delete all messages from individual favourited, no messages remaining, different user' => [
5984                  'conversationConfigs' => $conversations,
5985                  'deletemessagesuser' => $user1,
5986                  'deletemessages' => [0, 1, 2],
5987                  'arguments' => [$user2],
5988                  'expectedcounts' => ['favourites' => 1, 'types' => [
5989                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
5990                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 2,
5991                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5992                  ]],
5993                  'expectedunreadcounts' => ['favourites' => 0, 'types' => [
5994                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
5995                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 2,
5996                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
5997                  ]],
5998                  'deletedusers' => []
5999              ],
6000              'All conversation types, delete all messages from individual non-favourited, no messages remaining, different user' => [
6001                  'conversationConfigs' => $conversations,
6002                  'deletemessagesuser' => $user1,
6003                  'deletemessages' => [3, 4, 5],
6004                  'arguments' => [$user3],
6005                  'expectedcounts' => ['favourites' => 1, 'types' => [
6006                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
6007                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 2,
6008                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
6009                  ]],
6010                  'expectedunreadcounts' => ['favourites' => 0, 'types' => [
6011                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
6012                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 2,
6013                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
6014                  ]],
6015                  'deletedusers' => []
6016              ],
6017              'All conversation types, delete some messages from group non-favourited, messages remaining,' => [
6018                  'conversationConfigs' => $conversations,
6019                  'deletemessagesuser' => $user1,
6020                  'deletemessages' => [6, 7],
6021                  'arguments' => [$user1],
6022                  'expectedcounts' => ['favourites' => 2, 'types' => [
6023                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
6024                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 1,
6025                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
6026                  ]],
6027                  'expectedunreadcounts' => ['favourites' => 1, 'types' => [
6028                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
6029                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 1,
6030                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
6031                  ]],
6032                  'deletedusers' => []
6033              ],
6034              'All conversation types, delete all messages from group non-favourited, no messages remaining,' => [
6035                  'conversationConfigs' => $conversations,
6036                  'deletemessagesuser' => $user1,
6037                  'deletemessages' => [6, 7, 8, 9],
6038                  'arguments' => [$user1],
6039                  'expectedcounts' => ['favourites' => 2, 'types' => [
6040                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
6041                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 1,
6042                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
6043                  ]],
6044                  'expectedunreadcounts' => ['favourites' => 1, 'types' => [
6045                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
6046                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 0,
6047                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
6048                  ]],
6049                  'deletedusers' => []
6050              ],
6051              'All conversation types, another user soft deleted' => [
6052                  'conversationConfigs' => $conversations,
6053                  'deletemessagesuser' => null,
6054                  'deletemessages' => [],
6055                  'arguments' => [$user1],
6056                  'expectedcounts' => ['favourites' => 2, 'types' => [
6057                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
6058                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 1,
6059                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
6060                  ]],
6061                  'expectedunreadcounts' => ['favourites' => 1, 'types' => [
6062                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
6063                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 1,
6064                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
6065                  ]],
6066                  'deletedusers' => [$user2]
6067              ],
6068              'All conversation types, all group users soft deleted' => [
6069                  'conversationConfigs' => $conversations,
6070                  'deletemessagesuser' => null,
6071                  'deletemessages' => [],
6072                  'arguments' => [$user1],
6073                  'expectedcounts' => ['favourites' => 2, 'types' => [
6074                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
6075                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 1,
6076                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
6077                  ]],
6078                  'expectedunreadcounts' => ['favourites' => 1, 'types' => [
6079                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 1,
6080                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 1,
6081                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
6082                  ]],
6083                  'deletedusers' => [$user2, $user3, $user4]
6084              ],
6085              'Group conversation which is disabled, favourited' => [
6086                  'conversationConfigs' => $conversations,
6087                  'deletemessagesuser' => null,
6088                  'deletemessages' => [],
6089                  'arguments' => [$user6],
6090                  'expectedcounts' => ['favourites' => 1, 'types' => [
6091                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
6092                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 0,
6093                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
6094                  ]],
6095                  'expectedunreadcounts' => ['favourites' => 0, 'types' => [
6096                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
6097                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 0,
6098                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
6099                  ]],
6100                  'deletedusers' => []
6101              ],
6102              'Group conversation which is disabled, non-favourited' => [
6103                  'conversationConfigs' => $conversations,
6104                  'deletemessagesuser' => null,
6105                  'deletemessages' => [],
6106                  'arguments' => [$user7],
6107                  'expectedcounts' => ['favourites' => 1, 'types' => [
6108                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
6109                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 0,
6110                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
6111                  ]],
6112                  'expectedunreadcounts' => ['favourites' => 0, 'types' => [
6113                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
6114                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 0,
6115                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
6116                  ]],
6117                  'deletedusers' => []
6118              ],
6119              'Conversation with self' => [
6120                  'conversationConfigs' => $conversations,
6121                  'deletemessagesuser' => null,
6122                  'deletemessages' => [],
6123                  'arguments' => [$user8],
6124                  'expectedcounts' => ['favourites' => 0, 'types' => [
6125                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
6126                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 0,
6127                      api::MESSAGE_CONVERSATION_TYPE_SELF => 1
6128                  ]],
6129                  'expectedunreadcounts' => ['favourites' => 0, 'types' => [
6130                      api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL => 0,
6131                      api::MESSAGE_CONVERSATION_TYPE_GROUP => 0,
6132                      api::MESSAGE_CONVERSATION_TYPE_SELF => 0
6133                  ]],
6134                  'deletedusers' => []
6135              ],
6136          ];
6137      }
6138  
6139      /**
6140       * Test the get_conversation_counts() function.
6141       *
6142       * @dataProvider get_conversation_counts_test_cases
6143       * @param array $conversationconfigs Conversations to create
6144       * @param int $deletemessagesuser The user who is deleting the messages
6145       * @param array $deletemessages The list of messages to delete (by index)
6146       * @param array $arguments Arguments for the count conversations function
6147       * @param array $expectedcounts the expected conversation counts
6148       * @param array $expectedunreadcounts the expected unread conversation counts
6149       * @param array $deletedusers the array of users to soft delete.
6150       */
6151      public function test_get_conversation_counts(
6152          $conversationconfigs,
6153          $deletemessagesuser,
6154          $deletemessages,
6155          $arguments,
6156          $expectedcounts,
6157          $expectedunreadcounts,
6158          $deletedusers
6159      ) {
6160          $generator = $this->getDataGenerator();
6161          $users = [
6162              $generator->create_user(),
6163              $generator->create_user(),
6164              $generator->create_user(),
6165              $generator->create_user(),
6166              $generator->create_user(),
6167              $generator->create_user(),
6168              $generator->create_user(),
6169              $generator->create_user()
6170          ];
6171  
6172          $deleteuser = !is_null($deletemessagesuser) ? $users[$deletemessagesuser] : null;
6173          $arguments[0] = $users[$arguments[0]]->id;
6174          $systemcontext = \context_system::instance();
6175          $conversations = [];
6176          $messageids = [];
6177  
6178          foreach ($conversationconfigs as $config) {
6179              $conversation = api::create_conversation(
6180                  $config['type'],
6181                  array_map(function($userindex) use ($users) {
6182                      return $users[$userindex]->id;
6183                  }, $config['users']),
6184                  null,
6185                  ($config['enabled'] ?? true)
6186              );
6187  
6188              foreach ($config['messages'] as $userfromindex) {
6189                  $userfrom = $users[$userfromindex];
6190                  $messageids[] = testhelper::send_fake_message_to_conversation($userfrom, $conversation->id);
6191              }
6192  
6193              // Remove the self conversations created by the generator,
6194              // so we can choose to set that ourself and honour the original intention of the test.
6195              $userids = array_map(function($userindex) use ($users) {
6196                  return $users[$userindex]->id;
6197              }, $config['users']);
6198              foreach ($userids as $userid) {
6199                  if ($conversation->type == api::MESSAGE_CONVERSATION_TYPE_SELF) {
6200                      api::unset_favourite_conversation($conversation->id, $userid);
6201                  }
6202              }
6203  
6204              foreach ($config['favourites'] as $userfromindex) {
6205                  $userfrom = $users[$userfromindex];
6206                  $usercontext = \context_user::instance($userfrom->id);
6207                  $ufservice = \core_favourites\service_factory::get_service_for_user_context($usercontext);
6208                  $ufservice->create_favourite('core_message', 'message_conversations', $conversation->id, $systemcontext);
6209              }
6210  
6211              $conversations[] = $conversation;
6212          }
6213  
6214          foreach ($deletemessages as $messageindex) {
6215              api::delete_message($deleteuser->id, $messageids[$messageindex]);
6216          }
6217  
6218          foreach ($deletedusers as $deleteduser) {
6219              delete_user($users[$deleteduser]);
6220          }
6221  
6222          $counts = api::get_conversation_counts(...$arguments);
6223  
6224          $this->assertEquals($expectedcounts['favourites'], $counts['favourites']);
6225          $this->assertEquals($expectedcounts['types'][api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL],
6226              $counts['types'][api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL]);
6227          $this->assertEquals($expectedcounts['types'][api::MESSAGE_CONVERSATION_TYPE_GROUP],
6228              $counts['types'][api::MESSAGE_CONVERSATION_TYPE_GROUP]);
6229          $this->assertEquals($expectedcounts['types'][api::MESSAGE_CONVERSATION_TYPE_SELF],
6230              $counts['types'][api::MESSAGE_CONVERSATION_TYPE_SELF]);
6231      }
6232  
6233      /**
6234       * Test the count_contacts() function.
6235       */
6236      public function test_count_contacts() {
6237          $user1 = self::getDataGenerator()->create_user();
6238          $user2 = self::getDataGenerator()->create_user();
6239          $user3 = self::getDataGenerator()->create_user();
6240  
6241          $this->assertEquals(0, api::count_contacts($user1->id));
6242  
6243          api::create_contact_request($user1->id, $user2->id);
6244  
6245          // Still zero until the request is confirmed.
6246          $this->assertEquals(0, api::count_contacts($user1->id));
6247  
6248          api::confirm_contact_request($user1->id, $user2->id);
6249  
6250          $this->assertEquals(1, api::count_contacts($user1->id));
6251  
6252          api::create_contact_request($user3->id, $user1->id);
6253  
6254          // Still one until the request is confirmed.
6255          $this->assertEquals(1, api::count_contacts($user1->id));
6256  
6257          api::confirm_contact_request($user3->id, $user1->id);
6258  
6259          $this->assertEquals(2, api::count_contacts($user1->id));
6260      }
6261  
6262      /**
6263       * Test the get_unread_conversation_counts() function.
6264       *
6265       * @dataProvider get_conversation_counts_test_cases
6266       * @param array $conversationconfigs Conversations to create
6267       * @param int $deletemessagesuser The user who is deleting the messages
6268       * @param array $deletemessages The list of messages to delete (by index)
6269       * @param array $arguments Arguments for the count conversations function
6270       * @param array $expectedcounts the expected conversation counts
6271       * @param array $expectedunreadcounts the expected unread conversation counts
6272       * @param array $deletedusers the list of users to soft-delete.
6273       */
6274      public function test_get_unread_conversation_counts(
6275          $conversationconfigs,
6276          $deletemessagesuser,
6277          $deletemessages,
6278          $arguments,
6279          $expectedcounts,
6280          $expectedunreadcounts,
6281          $deletedusers
6282      ) {
6283          $this->resetAfterTest();
6284          $generator = $this->getDataGenerator();
6285          $users = [
6286              $generator->create_user(),
6287              $generator->create_user(),
6288              $generator->create_user(),
6289              $generator->create_user(),
6290              $generator->create_user(),
6291              $generator->create_user(),
6292              $generator->create_user(),
6293              $generator->create_user()
6294          ];
6295  
6296          $deleteuser = !is_null($deletemessagesuser) ? $users[$deletemessagesuser] : null;
6297          $this->setUser($users[$arguments[0]]);
6298          $arguments[0] = $users[$arguments[0]]->id;
6299          $systemcontext = \context_system::instance();
6300          $conversations = [];
6301          $messageids = [];
6302  
6303          foreach ($conversationconfigs as $config) {
6304              $conversation = api::create_conversation(
6305                  $config['type'],
6306                  array_map(function($userindex) use ($users) {
6307                      return $users[$userindex]->id;
6308                  }, $config['users']),
6309                  null,
6310                  ($config['enabled'] ?? true)
6311              );
6312  
6313              foreach ($config['messages'] as $userfromindex) {
6314                  $userfrom = $users[$userfromindex];
6315                  $messageids[] = testhelper::send_fake_message_to_conversation($userfrom, $conversation->id);
6316              }
6317  
6318              foreach ($config['favourites'] as $userfromindex) {
6319                  $userfrom = $users[$userfromindex];
6320                  $usercontext = \context_user::instance($userfrom->id);
6321                  $ufservice = \core_favourites\service_factory::get_service_for_user_context($usercontext);
6322                  $ufservice->create_favourite('core_message', 'message_conversations', $conversation->id, $systemcontext);
6323              }
6324  
6325              $conversations[] = $conversation;
6326          }
6327  
6328          foreach ($deletemessages as $messageindex) {
6329              api::delete_message($deleteuser->id, $messageids[$messageindex]);
6330          }
6331  
6332          foreach ($deletedusers as $deleteduser) {
6333              delete_user($users[$deleteduser]);
6334          }
6335  
6336          $counts = api::get_unread_conversation_counts(...$arguments);
6337  
6338          $this->assertEquals($expectedunreadcounts['favourites'], $counts['favourites']);
6339          $this->assertEquals($expectedunreadcounts['types'][api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL],
6340              $counts['types'][api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL]);
6341          $this->assertEquals($expectedunreadcounts['types'][api::MESSAGE_CONVERSATION_TYPE_GROUP],
6342              $counts['types'][api::MESSAGE_CONVERSATION_TYPE_GROUP]);
6343          $this->assertEquals($expectedunreadcounts['types'][api::MESSAGE_CONVERSATION_TYPE_SELF],
6344              $counts['types'][api::MESSAGE_CONVERSATION_TYPE_SELF]);
6345      }
6346  
6347      public function test_delete_all_conversation_data() {
6348          global $DB;
6349  
6350          $this->resetAfterTest();
6351  
6352          $this->setAdminUser();
6353  
6354          $course1 = $this->getDataGenerator()->create_course();
6355          $coursecontext1 = \context_course::instance($course1->id);
6356  
6357          $user1 = $this->getDataGenerator()->create_user();
6358          $user2 = $this->getDataGenerator()->create_user();
6359  
6360          $this->getDataGenerator()->enrol_user($user1->id, $course1->id);
6361          $this->getDataGenerator()->enrol_user($user2->id, $course1->id);
6362  
6363          $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course1->id, 'enablemessaging' => 1));
6364          $group2 = $this->getDataGenerator()->create_group(array('courseid' => $course1->id, 'enablemessaging' => 1));
6365  
6366          // Add users to both groups.
6367          $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user1->id));
6368          $this->getDataGenerator()->create_group_member(array('groupid' => $group1->id, 'userid' => $user2->id));
6369  
6370          $this->getDataGenerator()->create_group_member(array('groupid' => $group2->id, 'userid' => $user1->id));
6371          $this->getDataGenerator()->create_group_member(array('groupid' => $group2->id, 'userid' => $user2->id));
6372  
6373          $groupconversation1 = api::get_conversation_by_area(
6374              'core_group',
6375              'groups',
6376              $group1->id,
6377              $coursecontext1->id
6378          );
6379  
6380          $groupconversation2 = api::get_conversation_by_area(
6381              'core_group',
6382              'groups',
6383              $group2->id,
6384              $coursecontext1->id
6385          );
6386  
6387          // Send a few messages.
6388          $g1m1 = testhelper::send_fake_message_to_conversation($user1, $groupconversation1->id);
6389          $g1m2 = testhelper::send_fake_message_to_conversation($user2, $groupconversation1->id);
6390          $g1m3 = testhelper::send_fake_message_to_conversation($user1, $groupconversation1->id);
6391          $g1m4 = testhelper::send_fake_message_to_conversation($user2, $groupconversation1->id);
6392  
6393          $g2m1 = testhelper::send_fake_message_to_conversation($user1, $groupconversation2->id);
6394          $g2m2 = testhelper::send_fake_message_to_conversation($user2, $groupconversation2->id);
6395          $g2m3 = testhelper::send_fake_message_to_conversation($user1, $groupconversation2->id);
6396          $g2m4 = testhelper::send_fake_message_to_conversation($user2, $groupconversation2->id);
6397  
6398          // Favourite the conversation for several of the users.
6399          api::set_favourite_conversation($groupconversation1->id, $user1->id);
6400          api::set_favourite_conversation($groupconversation1->id, $user2->id);
6401  
6402          // Delete a few messages.
6403          api::delete_message($user1->id, $g1m1);
6404          api::delete_message($user1->id, $g1m2);
6405          api::delete_message($user1->id, $g2m1);
6406          api::delete_message($user1->id, $g2m2);
6407  
6408          // Mute the conversations.
6409          api::mute_conversation($user1->id, $groupconversation1->id);
6410          api::mute_conversation($user1->id, $groupconversation2->id);
6411  
6412          // Now, delete all the data for the group 1 conversation.
6413          api::delete_all_conversation_data($groupconversation1->id);
6414  
6415          // Confirm group conversation was deleted just for the group 1 conversation.
6416          $this->assertEquals(0, $DB->count_records('message_conversations', ['id' => $groupconversation1->id]));
6417          $this->assertEquals(1, $DB->count_records('message_conversations', ['id' => $groupconversation2->id]));
6418  
6419          // Confirm conversation members were deleted just for the group 1 conversation.
6420          $this->assertEquals(0, $DB->count_records('message_conversation_members', ['conversationid' => $groupconversation1->id]));
6421          $this->assertEquals(2, $DB->count_records('message_conversation_members', ['conversationid' => $groupconversation2->id]));
6422  
6423          // Confirm message conversation actions were deleted just for the group 1 conversation.
6424          $this->assertEquals(0, $DB->count_records('message_conversation_actions', ['conversationid' => $groupconversation1->id]));
6425          $this->assertEquals(1, $DB->count_records('message_conversation_actions', ['conversationid' => $groupconversation2->id]));
6426  
6427          // Confirm message user actions were deleted just for the group 1 conversation.
6428          $this->assertEquals(0, $DB->count_records('message_user_actions', ['messageid' => $g1m1]));
6429          $this->assertEquals(0, $DB->count_records('message_user_actions', ['messageid' => $g1m2]));
6430          $this->assertEquals(0, $DB->count_records('message_user_actions', ['messageid' => $g1m3]));
6431          $this->assertEquals(0, $DB->count_records('message_user_actions', ['messageid' => $g1m4]));
6432          $this->assertEquals(1, $DB->count_records('message_user_actions', ['messageid' => $g2m1]));
6433          $this->assertEquals(1, $DB->count_records('message_user_actions', ['messageid' => $g2m2]));
6434          $this->assertEquals(0, $DB->count_records('message_user_actions', ['messageid' => $g2m3]));
6435          $this->assertEquals(0, $DB->count_records('message_user_actions', ['messageid' => $g2m4]));
6436  
6437          // Confirm messages were deleted just for the group 1 conversation.
6438          $this->assertEquals(0, $DB->count_records('messages', ['id' => $g1m1]));
6439          $this->assertEquals(0, $DB->count_records('messages', ['id' => $g1m2]));
6440          $this->assertEquals(0, $DB->count_records('messages', ['id' => $g1m3]));
6441          $this->assertEquals(0, $DB->count_records('messages', ['id' => $g1m4]));
6442          $this->assertEquals(1, $DB->count_records('messages', ['id' => $g2m1]));
6443          $this->assertEquals(1, $DB->count_records('messages', ['id' => $g2m2]));
6444          $this->assertEquals(1, $DB->count_records('messages', ['id' => $g2m3]));
6445          $this->assertEquals(1, $DB->count_records('messages', ['id' => $g2m4]));
6446  
6447          // Confirm favourites were deleted for both users.
6448          $user1service = \core_favourites\service_factory::get_service_for_user_context(\context_user::instance($user1->id));
6449          $this->assertFalse($user1service->favourite_exists('core_message', 'message_conversations', $groupconversation1->id,
6450              $coursecontext1));
6451          $user2service = \core_favourites\service_factory::get_service_for_user_context(\context_user::instance($user1->id));
6452          $this->assertFalse($user2service->favourite_exists('core_message', 'message_conversations', $groupconversation1->id,
6453              $coursecontext1));
6454      }
6455  
6456      /**
6457       * Tests the user can delete message for all users as a teacher.
6458       */
6459      public function test_can_delete_message_for_all_users_teacher() {
6460          global $DB;
6461          $this->resetAfterTest(true);
6462  
6463          // Create fake data to test it.
6464          list($teacher, $student1, $student2, $convgroup, $convindividual) = $this->create_delete_message_test_data();
6465  
6466          // Allow Teacher can delete messages for all.
6467          $editingteacher = $DB->get_record('role', ['shortname' => 'editingteacher']);
6468          assign_capability('moodle/site:deleteanymessage', CAP_ALLOW, $editingteacher->id, \context_system::instance());
6469  
6470          // Set as the first user.
6471          $this->setUser($teacher);
6472  
6473          // Send a message to private conversation and in a group conversation.
6474          $messageidind = testhelper::send_fake_message_to_conversation($teacher, $convindividual->id);
6475          $messageidgrp = testhelper::send_fake_message_to_conversation($teacher, $convgroup->id);
6476  
6477          // Teacher cannot delete message for everyone in a private conversation.
6478          $this->assertFalse(api::can_delete_message_for_all_users($teacher->id, $messageidind));
6479  
6480          // Teacher can delete message for everyone in a group conversation.
6481          $this->assertTrue(api::can_delete_message_for_all_users($teacher->id, $messageidgrp));
6482      }
6483  
6484      /**
6485       * Tests the user can delete message for all users as a student.
6486       */
6487      public function test_can_delete_message_for_all_users_student() {
6488          $this->resetAfterTest(true);
6489  
6490          // Create fake data to test it.
6491          list($teacher, $student1, $student2, $convgroup, $convindividual) = $this->create_delete_message_test_data();
6492  
6493          // Set as the first user.
6494          $this->setUser($student1);
6495  
6496          // Send a message to private conversation and in a group conversation.
6497          $messageidind = testhelper::send_fake_message_to_conversation($teacher, $convindividual->id);
6498          $messageidgrp = testhelper::send_fake_message_to_conversation($teacher, $convgroup->id);
6499  
6500          // Student1 cannot delete message for everyone in a private conversation.
6501          $this->assertFalse(api::can_delete_message_for_all_users($student1->id, $messageidind));
6502  
6503          // Student1 cannot delete message for everyone in a group conversation.
6504          $this->assertFalse(api::can_delete_message_for_all_users($student1->id, $messageidgrp));
6505      }
6506  
6507      /**
6508       * Tests tdelete message for all users in group conversation.
6509       */
6510      public function test_delete_message_for_all_users_group_conversation() {
6511          global $DB;
6512          $this->resetAfterTest(true);
6513  
6514          // Create fake data to test it.
6515          list($teacher, $student1, $student2, $convgroup, $convindividual) = $this->create_delete_message_test_data();
6516  
6517          // Send 3 messages to a group conversation.
6518          $mgid1 = testhelper::send_fake_message_to_conversation($teacher, $convgroup->id);
6519          $mgid2 = testhelper::send_fake_message_to_conversation($student1, $convgroup->id);
6520          $mgid3 = testhelper::send_fake_message_to_conversation($student2, $convgroup->id);
6521  
6522          // Delete message 1 for all users.
6523          api::delete_message_for_all_users($mgid1);
6524  
6525          // Get the messages to check if the message 1 was deleted for teacher.
6526          $convmessages1 = api::get_conversation_messages($teacher->id, $convgroup->id);
6527          // Only has to remains 2 messages.
6528          $this->assertCount(2, $convmessages1['messages']);
6529          // Check if no one of the two messages is message 1.
6530          foreach ($convmessages1['messages'] as $message) {
6531              $this->assertNotEquals($mgid1, $message->id);
6532          }
6533  
6534          // Get the messages to check if the message 1 was deleted for student1.
6535          $convmessages2 = api::get_conversation_messages($student1->id, $convgroup->id);
6536          // Only has to remains 2 messages.
6537          $this->assertCount(2, $convmessages2['messages']);
6538          // Check if no one of the two messages is message 1.
6539          foreach ($convmessages2['messages'] as $message) {
6540              $this->assertNotEquals($mgid1, $message->id);
6541          }
6542  
6543          // Get the messages to check if the message 1 was deleted for student2.
6544          $convmessages3 = api::get_conversation_messages($student2->id, $convgroup->id);
6545          // Only has to remains 2 messages.
6546          $this->assertCount(2, $convmessages3['messages']);
6547          // Check if no one of the two messages is message 1.
6548          foreach ($convmessages3['messages'] as $message) {
6549              $this->assertNotEquals($mgid1, $message->id);
6550          }
6551      }
6552  
6553      /**
6554       * Tests delete message for all users in private conversation.
6555       */
6556      public function test_delete_message_for_all_users_individual_conversation() {
6557          global $DB;
6558          $this->resetAfterTest(true);
6559  
6560          // Create fake data to test it.
6561          list($teacher, $student1, $student2, $convgroup, $convindividual) = $this->create_delete_message_test_data();
6562  
6563          // Send 2 messages in a individual conversation.
6564          $mid1 = testhelper::send_fake_message_to_conversation($teacher, $convindividual->id);
6565          $mid2 = testhelper::send_fake_message_to_conversation($student1, $convindividual->id);
6566  
6567          // Delete the first message for all users.
6568          api::delete_message_for_all_users($mid1);
6569  
6570          // Get the messages to check if the message 1 was deleted for teacher.
6571          $convmessages1 = api::get_conversation_messages($teacher->id, $convindividual->id);
6572          // Only has to remains 1 messages for teacher.
6573          $this->assertCount(1, $convmessages1['messages']);
6574          // Check the one messages remains not is the first message.
6575          $this->assertNotEquals($mid1, $convmessages1['messages'][0]->id);
6576  
6577          // Get the messages to check if the message 1 was deleted for student1.
6578          $convmessages2 = api::get_conversation_messages($student1->id, $convindividual->id);
6579          // Only has to remains 1 messages for student1.
6580          $this->assertCount(1, $convmessages2['messages']);
6581          // Check the one messages remains not is the first message.
6582          $this->assertNotEquals($mid1, $convmessages2['messages'][0]->id);
6583      }
6584  
6585      /**
6586       * Test retrieving conversation messages by providing a timefrom higher than last message timecreated. It should return no
6587       * messages but keep the return structure to not break when called from the ws.
6588       */
6589      public function test_get_conversation_messages_timefrom_higher_than_last_timecreated() {
6590          // Create some users.
6591          $user1 = self::getDataGenerator()->create_user();
6592          $user2 = self::getDataGenerator()->create_user();
6593          $user3 = self::getDataGenerator()->create_user();
6594          $user4 = self::getDataGenerator()->create_user();
6595  
6596          // Create group conversation.
6597          $conversation = api::create_conversation(
6598              api::MESSAGE_CONVERSATION_TYPE_GROUP,
6599              [$user1->id, $user2->id, $user3->id, $user4->id]
6600          );
6601  
6602          // The person doing the search.
6603          $this->setUser($user1);
6604  
6605          // Send some messages back and forth.
6606          $time = 1;
6607          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time + 1);
6608          testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time + 2);
6609          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 3', $time + 3);
6610          testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Message 4', $time + 4);
6611  
6612          // Retrieve the messages from $time + 5, which should return no messages.
6613          $convmessages = api::get_conversation_messages($user1->id, $conversation->id, 0, 0, '', $time + 5);
6614  
6615          // Confirm the conversation id is correct.
6616          $this->assertEquals($conversation->id, $convmessages['id']);
6617  
6618          // Confirm the message data is correct.
6619          $messages = $convmessages['messages'];
6620          $this->assertEquals(0, count($messages));
6621  
6622          // Confirm that members key is present.
6623          $this->assertArrayHasKey('members', $convmessages);
6624      }
6625  
6626      /**
6627       * Helper to seed the database with initial state with data.
6628       */
6629      protected function create_delete_message_test_data() {
6630          // Create some users.
6631          $teacher = self::getDataGenerator()->create_user();
6632          $student1 = self::getDataGenerator()->create_user();
6633          $student2 = self::getDataGenerator()->create_user();
6634  
6635          // Create a course and enrol the users.
6636          $course = $this->getDataGenerator()->create_course();
6637          $coursecontext = \context_course::instance($course->id);
6638          $this->getDataGenerator()->enrol_user($teacher->id, $course->id, 'editingteacher');
6639          $this->getDataGenerator()->enrol_user($student1->id, $course->id, 'student');
6640          $this->getDataGenerator()->enrol_user($student2->id, $course->id, 'student');
6641  
6642          // Create a group and added the users into.
6643          $group1 = $this->getDataGenerator()->create_group(array('courseid' => $course->id));
6644          groups_add_member($group1->id, $teacher->id);
6645          groups_add_member($group1->id, $student1->id);
6646          groups_add_member($group1->id, $student2->id);
6647  
6648          // Create a group conversation linked with the course.
6649          $convgroup = api::create_conversation(
6650              api::MESSAGE_CONVERSATION_TYPE_GROUP,
6651              [$teacher->id, $student1->id, $student2->id],
6652              'Group test delete for everyone', api::MESSAGE_CONVERSATION_ENABLED,
6653              'core_group',
6654              'groups',
6655              $group1->id,
6656              \context_course::instance($course->id)->id
6657          );
6658  
6659          // Create and individual conversation.
6660          $convindividual = api::create_conversation(
6661              api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
6662              [$teacher->id, $student1->id]
6663          );
6664  
6665          return [$teacher, $student1, $student2, $convgroup, $convindividual];
6666      }
6667  
6668      /**
6669       * Comparison function for sorting contacts.
6670       *
6671       * @param \stdClass $a
6672       * @param \stdClass $b
6673       * @return bool
6674       */
6675      protected static function sort_contacts($a, $b) {
6676          return $a->userid > $b->userid;
6677      }
6678  }