Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

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

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