Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

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

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