Search moodle.org's
Developer Documentation

  • Bug fixes for general core bugs in 3.11.x will end 9 May 2022 (12 months).
  • Bug fixes for security issues in 3.11.x will end 14 November 2022 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
  • Differences Between: [Versions 310 and 311] [Versions 35 and 311] [Versions 36 and 311] [Versions 37 and 311] [Versions 38 and 311] [Versions 39 and 311]

       1  <?php
       2  // This file is part of Moodle - http://moodle.org/
       3  //
       4  // Moodle is free software: you can redistribute it and/or modify
       5  // it under the terms of the GNU General Public License as published by
       6  // the Free Software Foundation, either version 3 of the License, or
       7  // (at your option) any later version.
       8  //
       9  // Moodle is distributed in the hope that it will be useful,
      10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12  // GNU General Public License for more details.
      13  //
      14  // You should have received a copy of the GNU General Public License
      15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
      16  
      17  /**
      18   * External message functions unit tests
      19   *
      20   * @package    core_message
      21   * @category   external
      22   * @copyright  2012 Jerome Mouneyrac
      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 . '/webservice/tests/helpers.php');
      31  require_once($CFG->dirroot . '/message/externallib.php');
      32  
      33  use \core_message\tests\helper as testhelper;
      34  
      35  class core_message_externallib_testcase extends externallib_advanced_testcase {
      36  
      37      /**
      38       * Tests set up
      39       */
      40      protected function setUp(): void {
      41          global $CFG;
      42  
      43          require_once($CFG->dirroot . '/message/lib.php');
      44      }
      45  
      46      /**
      47       * Send a fake message.
      48       *
      49       * {@link message_send()} does not support transaction, this function will simulate a message
      50       * sent from a user to another. We should stop using it once {@link message_send()} will support
      51       * transactions. This is not clean at all, this is just used to add rows to the table.
      52       *
      53       * @param stdClass $userfrom user object of the one sending the message.
      54       * @param stdClass $userto user object of the one receiving the message.
      55       * @param string $message message to send.
      56       * @param int $notification is the message a notification.
      57       * @param int $time the time the message was sent
      58       */
      59      protected function send_message($userfrom, $userto, $message = 'Hello world!', $notification = 0, $time = 0) {
      60          global $DB;
      61  
      62          if (empty($time)) {
      63              $time = time();
      64          }
      65  
      66          if ($notification) {
      67              $record = new stdClass();
      68              $record->useridfrom = $userfrom->id;
      69              $record->useridto = $userto->id;
      70              $record->subject = 'No subject';
      71              $record->fullmessage = $message;
      72              $record->smallmessage = $message;
      73              $record->timecreated = $time;
      74  
      75              return $DB->insert_record('notifications', $record);
      76          }
      77  
      78          if (!$conversationid = \core_message\api::get_conversation_between_users([$userfrom->id, $userto->id])) {
      79              $conversation = \core_message\api::create_conversation(
      80                  \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
      81                  [
      82                      $userfrom->id,
      83                      $userto->id
      84                  ]
      85              );
      86              $conversationid = $conversation->id;
      87          }
      88  
      89          // Ok, send the message.
      90          $record = new stdClass();
      91          $record->useridfrom = $userfrom->id;
      92          $record->conversationid = $conversationid;
      93          $record->subject = 'No subject';
      94          $record->fullmessage = $message;
      95          $record->smallmessage = $message;
      96          $record->timecreated = $time;
      97  
      98          return $DB->insert_record('messages', $record);
      99      }
     100  
     101      /**
     102       * Test send_instant_messages.
     103       */
     104      public function test_send_instant_messages() {
     105          global $DB, $USER;
     106  
     107          $this->resetAfterTest();
     108  
     109          // Transactions used in tests, tell phpunit use alternative reset method.
     110          $this->preventResetByRollback();
     111  
     112          $user1 = self::getDataGenerator()->create_user();
     113          $user2 = self::getDataGenerator()->create_user();
     114  
     115          $this->setUser($user1);
     116  
     117          // Create test message data.
     118          $message1 = array();
     119          $message1['touserid'] = $user2->id;
     120          $message1['text'] = 'the message.';
     121          $message1['clientmsgid'] = 4;
     122          $messages = array($message1);
     123  
     124          $sentmessages = core_message_external::send_instant_messages($messages);
     125          $sentmessages = external_api::clean_returnvalue(core_message_external::send_instant_messages_returns(), $sentmessages);
     126          $this->assertEquals(
     127              get_string('usercantbemessaged', 'message', fullname(\core_user::get_user($message1['touserid']))),
     128              array_pop($sentmessages)['errormessage']
     129          );
     130  
     131          // Add the user1 as a contact.
     132          \core_message\api::add_contact($user1->id, $user2->id);
     133  
     134          // Send message again. Now it should work properly.
     135          $sentmessages = core_message_external::send_instant_messages($messages);
     136          // We need to execute the return values cleaning process to simulate the web service server.
     137          $sentmessages = external_api::clean_returnvalue(core_message_external::send_instant_messages_returns(), $sentmessages);
     138  
     139          $sentmessage = reset($sentmessages);
     140  
     141          $sql = "SELECT m.*, mcm.userid as useridto
     142                   FROM {messages} m
     143             INNER JOIN {message_conversations} mc
     144                     ON m.conversationid = mc.id
     145             INNER JOIN {message_conversation_members} mcm
     146                     ON mcm.conversationid = mc.id
     147                  WHERE mcm.userid != ?
     148                    AND m.id = ?";
     149          $themessage = $DB->get_record_sql($sql, [$USER->id, $sentmessage['msgid']]);
     150  
     151          // Confirm that the message was inserted correctly.
     152          $this->assertEquals($themessage->useridfrom, $user1->id);
     153          $this->assertEquals($themessage->useridto, $message1['touserid']);
     154          $this->assertEquals($themessage->smallmessage, $message1['text']);
     155          $this->assertEquals($sentmessage['clientmsgid'], $message1['clientmsgid']);
     156      }
     157  
     158      /**
     159       * Test send_instant_messages with a message text longer than permitted.
     160       */
     161      public function test_send_instant_messages_long_text() {
     162          global $CFG;
     163  
     164          $this->resetAfterTest(true);
     165  
     166          // Transactions used in tests, tell phpunit use alternative reset method.
     167          $this->preventResetByRollback();
     168  
     169          $user1 = self::getDataGenerator()->create_user();
     170          $user2 = self::getDataGenerator()->create_user();
     171  
     172          $this->setUser($user1);
     173  
     174          // Create test message data.
     175          $message1 = [
     176              'touserid' => $user2->id,
     177              'text' => str_repeat("M", \core_message\api::MESSAGE_MAX_LENGTH + 100),
     178              'clientmsgid' => 4,
     179          ];
     180          $messages = [$message1];
     181  
     182          // Add the user1 as a contact.
     183          \core_message\api::add_contact($user1->id, $user2->id);
     184  
     185          $sentmessages = core_message_external::send_instant_messages($messages);
     186          $sentmessages = external_api::clean_returnvalue(core_message_external::send_instant_messages_returns(), $sentmessages);
     187          $this->assertEquals(
     188              get_string('errormessagetoolong', 'message'),
     189              array_pop($sentmessages)['errormessage']
     190          );
     191      }
     192  
     193      /**
     194       * Test send_instant_messages to a user who has blocked you.
     195       */
     196      public function test_send_instant_messages_blocked_user() {
     197          global $DB;
     198  
     199          $this->resetAfterTest();
     200  
     201          // Transactions used in tests, tell phpunit use alternative reset method.
     202          $this->preventResetByRollback();
     203  
     204          $user1 = self::getDataGenerator()->create_user();
     205          $user2 = self::getDataGenerator()->create_user();
     206  
     207          $this->setUser($user1);
     208  
     209          \core_message\api::block_user($user2->id, $user1->id);
     210  
     211          // Create test message data.
     212          $message1 = array();
     213          $message1['touserid'] = $user2->id;
     214          $message1['text'] = 'the message.';
     215          $message1['clientmsgid'] = 4;
     216          $messages = array($message1);
     217  
     218          $sentmessages = core_message_external::send_instant_messages($messages);
     219          $sentmessages = external_api::clean_returnvalue(core_message_external::send_instant_messages_returns(), $sentmessages);
     220  
     221          $sentmessage = reset($sentmessages);
     222  
     223          $this->assertEquals(get_string('usercantbemessaged', 'message', fullname($user2)), $sentmessage['errormessage']);
     224  
     225          $this->assertEquals(0, $DB->count_records('messages'));
     226      }
     227  
     228      /**
     229       * Test send_instant_messages when sending a message to a non-contact who has blocked non-contacts.
     230       */
     231      public function test_send_instant_messages_block_non_contacts() {
     232          global $DB;
     233  
     234          $this->resetAfterTest(true);
     235  
     236          // Transactions used in tests, tell phpunit use alternative reset method.
     237          $this->preventResetByRollback();
     238  
     239          $user1 = self::getDataGenerator()->create_user();
     240          $user2 = self::getDataGenerator()->create_user();
     241  
     242          $this->setUser($user1);
     243  
     244          // Set the user preference so user 2 does not accept messages from non-contacts.
     245          set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2);
     246  
     247          // Create test message data.
     248          $message1 = array();
     249          $message1['touserid'] = $user2->id;
     250          $message1['text'] = 'the message.';
     251          $message1['clientmsgid'] = 4;
     252          $messages = array($message1);
     253  
     254          $sentmessages = core_message_external::send_instant_messages($messages);
     255          $sentmessages = external_api::clean_returnvalue(core_message_external::send_instant_messages_returns(), $sentmessages);
     256  
     257          $sentmessage = reset($sentmessages);
     258  
     259          $this->assertEquals(get_string('usercantbemessaged', 'message', fullname($user2)), $sentmessage['errormessage']);
     260  
     261          $this->assertEquals(0, $DB->count_records('messages'));
     262      }
     263  
     264      /**
     265       * Test send_instant_messages when sending a message to a contact who has blocked non-contacts.
     266       */
     267      public function test_send_instant_messages_block_non_contacts_but_am_contact() {
     268          global $DB, $USER;
     269  
     270          $this->resetAfterTest(true);
     271  
     272          // Transactions used in tests, tell phpunit use alternative reset method.
     273          $this->preventResetByRollback();
     274  
     275          $user1 = self::getDataGenerator()->create_user();
     276          $user2 = self::getDataGenerator()->create_user();
     277  
     278          $this->setUser($user1);
     279  
     280          // Set the user preference so user 2 does not accept messages from non-contacts.
     281          set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2);
     282  
     283          \core_message\api::add_contact($user1->id, $user2->id);
     284  
     285          // Create test message data.
     286          $message1 = array();
     287          $message1['touserid'] = $user2->id;
     288          $message1['text'] = 'the message.';
     289          $message1['clientmsgid'] = 4;
     290          $messages = array($message1);
     291  
     292          $sentmessages = core_message_external::send_instant_messages($messages);
     293          $sentmessages = external_api::clean_returnvalue(core_message_external::send_instant_messages_returns(), $sentmessages);
     294  
     295          $sentmessage = reset($sentmessages);
     296  
     297          $sql = "SELECT m.*, mcm.userid as useridto
     298                   FROM {messages} m
     299             INNER JOIN {message_conversations} mc
     300                     ON m.conversationid = mc.id
     301             INNER JOIN {message_conversation_members} mcm
     302                     ON mcm.conversationid = mc.id
     303                  WHERE mcm.userid != ?
     304                    AND m.id = ?";
     305          $themessage = $DB->get_record_sql($sql, [$USER->id, $sentmessage['msgid']]);
     306  
     307          // Confirm that the message was inserted correctly.
     308          $this->assertEquals($themessage->useridfrom, $user1->id);
     309          $this->assertEquals($themessage->useridto, $message1['touserid']);
     310          $this->assertEquals($themessage->smallmessage, $message1['text']);
     311          $this->assertEquals($sentmessage['clientmsgid'], $message1['clientmsgid']);
     312      }
     313  
     314      /**
     315       * Test send_instant_messages with no capabilities
     316       */
     317      public function test_send_instant_messages_no_capability() {
     318          global $DB;
     319  
     320          $this->resetAfterTest(true);
     321  
     322          // Transactions used in tests, tell phpunit use alternative reset method.
     323          $this->preventResetByRollback();
     324  
     325          $user1 = self::getDataGenerator()->create_user();
     326          $user2 = self::getDataGenerator()->create_user();
     327  
     328          $this->setUser($user1);
     329  
     330          // Unset the required capabilities by the external function.
     331          $contextid = context_system::instance()->id;
     332          $userrole = $DB->get_record('role', array('shortname' => 'user'));
     333          $this->unassignUserCapability('moodle/site:sendmessage', $contextid, $userrole->id);
     334  
     335          // Create test message data.
     336          $message1 = array();
     337          $message1['touserid'] = $user2->id;
     338          $message1['text'] = 'the message.';
     339          $message1['clientmsgid'] = 4;
     340          $messages = array($message1);
     341  
     342          $this->expectException('required_capability_exception');
     343          core_message_external::send_instant_messages($messages);
     344      }
     345  
     346      /**
     347       * Test send_instant_messages when messaging is disabled.
     348       */
     349      public function test_send_instant_messages_messaging_disabled() {
     350          global $CFG;
     351  
     352          $this->resetAfterTest(true);
     353  
     354          // Transactions used in tests, tell phpunit use alternative reset method.
     355          $this->preventResetByRollback();
     356  
     357          $user1 = self::getDataGenerator()->create_user();
     358          $user2 = self::getDataGenerator()->create_user();
     359  
     360          $this->setUser($user1);
     361  
     362          // Disable messaging.
     363          $CFG->messaging = 0;
     364  
     365          // Create test message data.
     366          $message1 = array();
     367          $message1['touserid'] = $user2->id;
     368          $message1['text'] = 'the message.';
     369          $message1['clientmsgid'] = 4;
     370          $messages = array($message1);
     371  
     372          $this->expectException('moodle_exception');
     373          core_message_external::send_instant_messages($messages);
     374      }
     375  
     376      /**
     377       * Test delete_contacts.
     378       */
     379      public function test_delete_contacts() {
     380          $this->resetAfterTest(true);
     381  
     382          $user1 = self::getDataGenerator()->create_user();
     383          $user2 = self::getDataGenerator()->create_user();
     384          $user3 = self::getDataGenerator()->create_user();
     385          $user4 = self::getDataGenerator()->create_user();
     386          $user5 = self::getDataGenerator()->create_user();
     387          $user6 = self::getDataGenerator()->create_user();
     388          $this->setUser($user1);
     389  
     390          \core_message\api::add_contact($user1->id, $user3->id);
     391          \core_message\api::add_contact($user1->id, $user4->id);
     392          \core_message\api::add_contact($user1->id, $user5->id);
     393          \core_message\api::add_contact($user1->id, $user6->id);
     394  
     395          // Removing a non-contact.
     396          $return = core_message_external::delete_contacts(array($user2->id));
     397          $this->assertNull($return);
     398  
     399          // Removing one contact.
     400          $return = core_message_external::delete_contacts(array($user3->id));
     401          $this->assertNull($return);
     402  
     403          // Removing multiple contacts.
     404          $return = core_message_external::delete_contacts(array($user4->id, $user5->id));
     405          $this->assertNull($return);
     406  
     407          // Removing contact from unexisting user.
     408          $return = core_message_external::delete_contacts(array(99999));
     409          $this->assertNull($return);
     410  
     411          // Removing mixed valid and invalid data.
     412          $return = core_message_external::delete_contacts(array($user6->id, 99999));
     413          $this->assertNull($return);
     414  
     415          // Try to delete a contact of another user contact list, should throw an exception.
     416          // All assertions must be added before this point.
     417          $this->expectException('required_capability_exception');
     418          core_message_external::delete_contacts(array($user2->id), $user3->id);
     419      }
     420  
     421      /**
     422       * Test getting contact requests.
     423       */
     424      public function test_get_contact_requests() {
     425          global $PAGE;
     426  
     427          $this->resetAfterTest();
     428  
     429          $user1 = self::getDataGenerator()->create_user();
     430          $user2 = self::getDataGenerator()->create_user();
     431          $user3 = self::getDataGenerator()->create_user();
     432  
     433          $this->setUser($user1);
     434  
     435          // Block one user, their request should not show up.
     436          \core_message\api::block_user($user1->id, $user3->id);
     437  
     438          \core_message\api::create_contact_request($user2->id, $user1->id);
     439          \core_message\api::create_contact_request($user3->id, $user1->id);
     440  
     441          $requests = core_message_external::get_contact_requests($user1->id);
     442          $requests = external_api::clean_returnvalue(core_message_external::get_contact_requests_returns(), $requests);
     443  
     444          $this->assertCount(1, $requests);
     445  
     446          $request = reset($requests);
     447          $userpicture = new \user_picture($user2);
     448          $profileimageurl = $userpicture->get_url($PAGE)->out(false);
     449  
     450          $this->assertEquals($user2->id, $request['id']);
     451          $this->assertEquals(fullname($user2), $request['fullname']);
     452          $this->assertArrayHasKey('profileimageurl', $request);
     453          $this->assertArrayHasKey('profileimageurlsmall', $request);
     454          $this->assertArrayHasKey('isonline', $request);
     455          $this->assertArrayHasKey('showonlinestatus', $request);
     456          $this->assertArrayHasKey('isblocked', $request);
     457          $this->assertArrayHasKey('iscontact', $request);
     458      }
     459  
     460      /**
     461       * Test the get_contact_requests() function when the user has blocked the sender of the request.
     462       */
     463      public function test_get_contact_requests_blocked_sender() {
     464          $this->resetAfterTest();
     465          $user1 = self::getDataGenerator()->create_user();
     466          $user2 = self::getDataGenerator()->create_user();
     467  
     468          // User1 blocks User2.
     469          \core_message\api::block_user($user1->id, $user2->id);
     470  
     471          // User2 tries to add User1 as a contact.
     472          \core_message\api::create_contact_request($user2->id, $user1->id);
     473  
     474          // Verify we don't see the contact request from the blocked user User2 in the requests for User1.
     475          $this->setUser($user1);
     476          $requests = core_message_external::get_contact_requests($user1->id);
     477          $requests = external_api::clean_returnvalue(core_message_external::get_contact_requests_returns(), $requests);
     478  
     479          $this->assertCount(0, $requests);
     480      }
     481  
     482      /**
     483       * Test getting contact requests when there are none.
     484       */
     485      public function test_get_contact_requests_no_requests() {
     486          $this->resetAfterTest();
     487  
     488          $user1 = self::getDataGenerator()->create_user();
     489  
     490          $this->setUser($user1);
     491  
     492          $requests = core_message_external::get_contact_requests($user1->id);
     493          $requests = external_api::clean_returnvalue(core_message_external::get_contact_requests_returns(), $requests);
     494  
     495          $this->assertEmpty($requests);
     496      }
     497  
     498      /**
     499       * Test getting contact requests with limits.
     500       */
     501      public function test_get_contact_requests_with_limits() {
     502          $this->resetAfterTest();
     503  
     504          $user1 = self::getDataGenerator()->create_user();
     505          $user2 = self::getDataGenerator()->create_user();
     506          $user3 = self::getDataGenerator()->create_user();
     507  
     508          $this->setUser($user1);
     509  
     510          \core_message\api::create_contact_request($user2->id, $user1->id);
     511          \core_message\api::create_contact_request($user3->id, $user1->id);
     512  
     513          $requests = core_message_external::get_contact_requests($user1->id, 0, 1);
     514          $requests = external_api::clean_returnvalue(core_message_external::get_contact_requests_returns(), $requests);
     515  
     516          $this->assertCount(1, $requests);
     517      }
     518  
     519      /**
     520       * Test getting contact requests with messaging disabled.
     521       */
     522      public function test_get_contact_requests_messaging_disabled() {
     523          global $CFG;
     524  
     525          $this->resetAfterTest();
     526  
     527          // Create some skeleton data just so we can call the WS.
     528          $user1 = self::getDataGenerator()->create_user();
     529  
     530          $this->setUser($user1);
     531  
     532          // Disable messaging.
     533          $CFG->messaging = 0;
     534  
     535          // Ensure an exception is thrown.
     536          $this->expectException('moodle_exception');
     537          core_message_external::get_contact_requests($user1->id);
     538      }
     539  
     540      /**
     541       * Test getting contact requests with no permission.
     542       */
     543      public function test_get_contact_requests_no_permission() {
     544          $this->resetAfterTest();
     545  
     546          // Create some skeleton data just so we can call the WS.
     547          $user1 = self::getDataGenerator()->create_user();
     548          $user2 = self::getDataGenerator()->create_user();
     549          $user3 = self::getDataGenerator()->create_user();
     550  
     551          $this->setUser($user3);
     552  
     553          // Ensure an exception is thrown.
     554          $this->expectException('required_capability_exception');
     555          core_message_external::create_contact_request($user1->id, $user2->id);
     556      }
     557  
     558      /**
     559       * Test getting the number of received contact requests.
     560       */
     561      public function test_get_received_contact_requests_count() {
     562          $this->resetAfterTest();
     563  
     564          $user1 = self::getDataGenerator()->create_user();
     565          $user2 = self::getDataGenerator()->create_user();
     566          $user3 = self::getDataGenerator()->create_user();
     567          $user4 = self::getDataGenerator()->create_user();
     568  
     569          $this->setUser($user1);
     570  
     571          $contactrequestnumber = core_message_external::get_received_contact_requests_count($user1->id);
     572          $contactrequestnumber = external_api::clean_returnvalue(
     573              core_message_external::get_received_contact_requests_count_returns(), $contactrequestnumber);
     574          $this->assertEquals(0, $contactrequestnumber);
     575  
     576          \core_message\api::create_contact_request($user2->id, $user1->id);
     577  
     578          $contactrequestnumber = core_message_external::get_received_contact_requests_count($user1->id);
     579          $contactrequestnumber = external_api::clean_returnvalue(
     580              core_message_external::get_received_contact_requests_count_returns(), $contactrequestnumber);
     581          $this->assertEquals(1, $contactrequestnumber);
     582  
     583          \core_message\api::create_contact_request($user3->id, $user1->id);
     584  
     585          $contactrequestnumber = core_message_external::get_received_contact_requests_count($user1->id);
     586          $contactrequestnumber = external_api::clean_returnvalue(
     587              core_message_external::get_received_contact_requests_count_returns(), $contactrequestnumber);
     588          $this->assertEquals(2, $contactrequestnumber);
     589  
     590          \core_message\api::create_contact_request($user1->id, $user4->id);
     591  
     592          // Web service should ignore sent requests.
     593          $contactrequestnumber = core_message_external::get_received_contact_requests_count($user1->id);
     594          $contactrequestnumber = external_api::clean_returnvalue(
     595              core_message_external::get_received_contact_requests_count_returns(), $contactrequestnumber);
     596          $this->assertEquals(2, $contactrequestnumber);
     597      }
     598  
     599      /**
     600       * Test the get_received_contact_requests_count() function when the user has blocked the sender of the request.
     601       */
     602      public function test_get_received_contact_requests_count_blocked_sender() {
     603          $this->resetAfterTest();
     604          $user1 = self::getDataGenerator()->create_user();
     605          $user2 = self::getDataGenerator()->create_user();
     606  
     607          // User1 blocks User2.
     608          \core_message\api::block_user($user1->id, $user2->id);
     609  
     610          // User2 tries to add User1 as a contact.
     611          \core_message\api::create_contact_request($user2->id, $user1->id);
     612  
     613          // Verify we don't see the contact request from the blocked user User2 in the count for User1.
     614          $this->setUser($user1);
     615          $contactrequestnumber = core_message_external::get_received_contact_requests_count($user1->id);
     616          $contactrequestnumber = external_api::clean_returnvalue(
     617              core_message_external::get_received_contact_requests_count_returns(), $contactrequestnumber);
     618          $this->assertEquals(0, $contactrequestnumber);
     619      }
     620  
     621      /**
     622       * Test getting the number of received contact requests with no permissions.
     623       */
     624      public function test_get_received_contact_requests_count_no_permission() {
     625          $this->resetAfterTest();
     626  
     627          // Create some skeleton data just so we can call the WS.
     628          $user1 = self::getDataGenerator()->create_user();
     629          $user2 = self::getDataGenerator()->create_user();
     630  
     631          $this->setUser($user2);
     632  
     633          // Ensure an exception is thrown.
     634          $this->expectException('required_capability_exception');
     635          core_message_external::get_received_contact_requests_count($user1->id);
     636      }
     637  
     638      /**
     639       * Test getting the number of received contact requests with messaging disabled.
     640       */
     641      public function test_get_received_contact_requests_count_messaging_disabled() {
     642          global $CFG;
     643  
     644          $this->resetAfterTest();
     645  
     646          // Create some skeleton data just so we can call the WS.
     647          $user1 = self::getDataGenerator()->create_user();
     648  
     649          $this->setUser($user1);
     650  
     651          // Disable messaging.
     652          $CFG->messaging = 0;
     653  
     654          // Ensure an exception is thrown.
     655          $this->expectException('moodle_exception');
     656          core_message_external::get_received_contact_requests_count($user1->id);
     657      }
     658  
     659      /**
     660       * Test creating a contact request.
     661       */
     662      public function test_create_contact_request() {
     663          global $CFG, $DB;
     664  
     665          $this->resetAfterTest();
     666  
     667          $user1 = self::getDataGenerator()->create_user();
     668          $user2 = self::getDataGenerator()->create_user();
     669  
     670          $this->setUser($user1);
     671  
     672          // Allow users to message anyone site-wide.
     673          $CFG->messagingallusers = 1;
     674  
     675          $return = core_message_external::create_contact_request($user1->id, $user2->id);
     676          $return = external_api::clean_returnvalue(core_message_external::create_contact_request_returns(), $return);
     677          $this->assertEquals([], $return['warnings']);
     678  
     679          $request = $DB->get_records('message_contact_requests');
     680  
     681          $this->assertCount(1, $request);
     682  
     683          $request = reset($request);
     684  
     685          $this->assertEquals($request->id, $return['request']['id']);
     686          $this->assertEquals($request->userid, $return['request']['userid']);
     687          $this->assertEquals($request->requesteduserid, $return['request']['requesteduserid']);
     688          $this->assertEquals($request->timecreated, $return['request']['timecreated']);
     689      }
     690  
     691      /**
     692       * Test creating a contact request when not allowed.
     693       */
     694      public function test_create_contact_request_not_allowed() {
     695          global $CFG;
     696  
     697          $this->resetAfterTest();
     698  
     699          $user1 = self::getDataGenerator()->create_user();
     700          $user2 = self::getDataGenerator()->create_user();
     701  
     702          $this->setUser($user1);
     703  
     704          $CFG->messagingallusers = 0;
     705  
     706          $return = core_message_external::create_contact_request($user1->id, $user2->id);
     707          $return = external_api::clean_returnvalue(core_message_external::create_contact_request_returns(), $return);
     708  
     709          $warning = reset($return['warnings']);
     710  
     711          $this->assertEquals('user', $warning['item']);
     712          $this->assertEquals($user2->id, $warning['itemid']);
     713          $this->assertEquals('cannotcreatecontactrequest', $warning['warningcode']);
     714          $this->assertEquals('You are unable to create a contact request for this user', $warning['message']);
     715      }
     716  
     717      /**
     718       * Test creating a contact request with messaging disabled.
     719       */
     720      public function test_create_contact_request_messaging_disabled() {
     721          global $CFG;
     722  
     723          $this->resetAfterTest();
     724  
     725          // Create some skeleton data just so we can call the WS.
     726          $user1 = self::getDataGenerator()->create_user();
     727          $user2 = self::getDataGenerator()->create_user();
     728  
     729          $this->setUser($user1);
     730  
     731          // Disable messaging.
     732          $CFG->messaging = 0;
     733  
     734          // Ensure an exception is thrown.
     735          $this->expectException('moodle_exception');
     736          core_message_external::create_contact_request($user1->id, $user2->id);
     737      }
     738  
     739      /**
     740       * Test creating a contact request with no permission.
     741       */
     742      public function test_create_contact_request_no_permission() {
     743          $this->resetAfterTest();
     744  
     745          // Create some skeleton data just so we can call the WS.
     746          $user1 = self::getDataGenerator()->create_user();
     747          $user2 = self::getDataGenerator()->create_user();
     748          $user3 = self::getDataGenerator()->create_user();
     749  
     750          $this->setUser($user3);
     751  
     752          // Ensure an exception is thrown.
     753          $this->expectException('required_capability_exception');
     754          core_message_external::create_contact_request($user1->id, $user2->id);
     755      }
     756  
     757      /**
     758       * Test confirming a contact request.
     759       */
     760      public function test_confirm_contact_request() {
     761          global $DB;
     762  
     763          $this->resetAfterTest();
     764  
     765          $user1 = self::getDataGenerator()->create_user();
     766          $user2 = self::getDataGenerator()->create_user();
     767  
     768          $this->setUser($user1);
     769  
     770          \core_message\api::create_contact_request($user1->id, $user2->id);
     771  
     772          $this->setUser($user2);
     773  
     774          $return = core_message_external::confirm_contact_request($user1->id, $user2->id);
     775          $return = external_api::clean_returnvalue(core_message_external::confirm_contact_request_returns(), $return);
     776          $this->assertEquals(array(), $return);
     777  
     778          $this->assertEquals(0, $DB->count_records('message_contact_requests'));
     779  
     780          $contact = $DB->get_records('message_contacts');
     781  
     782          $this->assertCount(1, $contact);
     783  
     784          $contact = reset($contact);
     785  
     786          $this->assertEquals($user1->id, $contact->userid);
     787          $this->assertEquals($user2->id, $contact->contactid);
     788      }
     789  
     790      /**
     791       * Test confirming a contact request with messaging disabled.
     792       */
     793      public function test_confirm_contact_request_messaging_disabled() {
     794          global $CFG;
     795  
     796          $this->resetAfterTest();
     797  
     798          // Create some skeleton data just so we can call the WS.
     799          $user1 = self::getDataGenerator()->create_user();
     800          $user2 = self::getDataGenerator()->create_user();
     801  
     802          $this->setUser($user1);
     803  
     804          // Disable messaging.
     805          $CFG->messaging = 0;
     806  
     807          // Ensure an exception is thrown.
     808          $this->expectException('moodle_exception');
     809          core_message_external::confirm_contact_request($user1->id, $user2->id);
     810      }
     811  
     812      /**
     813       * Test confirming a contact request with no permission.
     814       */
     815      public function test_confirm_contact_request_no_permission() {
     816          $this->resetAfterTest();
     817  
     818          // Create some skeleton data just so we can call the WS.
     819          $user1 = self::getDataGenerator()->create_user();
     820          $user2 = self::getDataGenerator()->create_user();
     821          $user3 = self::getDataGenerator()->create_user();
     822  
     823          $this->setUser($user3);
     824  
     825          // Ensure an exception is thrown.
     826          $this->expectException('required_capability_exception');
     827          core_message_external::confirm_contact_request($user1->id, $user2->id);
     828      }
     829  
     830      /**
     831       * Test declining a contact request.
     832       */
     833      public function test_decline_contact_request() {
     834          global $DB;
     835  
     836          $this->resetAfterTest();
     837  
     838          $user1 = self::getDataGenerator()->create_user();
     839          $user2 = self::getDataGenerator()->create_user();
     840  
     841          $this->setUser($user1);
     842  
     843          \core_message\api::create_contact_request($user1->id, $user2->id);
     844  
     845          $this->setUser($user2);
     846  
     847          $return = core_message_external::decline_contact_request($user1->id, $user2->id);
     848          $return = external_api::clean_returnvalue(core_message_external::decline_contact_request_returns(), $return);
     849          $this->assertEquals(array(), $return);
     850  
     851          $this->assertEquals(0, $DB->count_records('message_contact_requests'));
     852          $this->assertEquals(0, $DB->count_records('message_contacts'));
     853      }
     854  
     855      /**
     856       * Test declining a contact request with messaging disabled.
     857       */
     858      public function test_decline_contact_request_messaging_disabled() {
     859          global $CFG;
     860  
     861          $this->resetAfterTest();
     862  
     863          // Create some skeleton data just so we can call the WS.
     864          $user1 = self::getDataGenerator()->create_user();
     865          $user2 = self::getDataGenerator()->create_user();
     866  
     867          $this->setUser($user1);
     868  
     869          // Disable messaging.
     870          $CFG->messaging = 0;
     871  
     872          // Ensure an exception is thrown.
     873          $this->expectException('moodle_exception');
     874          core_message_external::decline_contact_request($user1->id, $user2->id);
     875      }
     876  
     877      /**
     878       * Test declining a contact request with no permission.
     879       */
     880      public function test_decline_contact_request_no_permission() {
     881          $this->resetAfterTest();
     882  
     883          // Create some skeleton data just so we can call the WS.
     884          $user1 = self::getDataGenerator()->create_user();
     885          $user2 = self::getDataGenerator()->create_user();
     886          $user3 = self::getDataGenerator()->create_user();
     887  
     888          $this->setUser($user3);
     889  
     890          // Ensure an exception is thrown.
     891          $this->expectException('required_capability_exception');
     892          core_message_external::decline_contact_request($user1->id, $user2->id);
     893      }
     894  
     895      /**
     896       * Test muting conversations.
     897       */
     898      public function test_mute_conversations() {
     899          global $DB;
     900  
     901          $this->resetAfterTest(true);
     902  
     903          $user1 = self::getDataGenerator()->create_user();
     904          $user2 = self::getDataGenerator()->create_user();
     905  
     906          $conversation = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
     907              [$user1->id, $user2->id]);
     908  
     909          $this->setUser($user1);
     910  
     911          // Muting a conversation.
     912          $return = core_message_external::mute_conversations($user1->id, [$conversation->id]);
     913          $return = external_api::clean_returnvalue(core_message_external::mute_conversations_returns(), $return);
     914          $this->assertEquals(array(), $return);
     915  
     916          // Get list of muted conversations.
     917          $mca = $DB->get_record('message_conversation_actions', []);
     918  
     919          $this->assertEquals($user1->id, $mca->userid);
     920          $this->assertEquals($conversation->id, $mca->conversationid);
     921          $this->assertEquals(\core_message\api::CONVERSATION_ACTION_MUTED, $mca->action);
     922  
     923          // Muting a conversation that is already muted.
     924          $return = core_message_external::mute_conversations($user1->id, [$conversation->id]);
     925          $return = external_api::clean_returnvalue(core_message_external::mute_conversations_returns(), $return);
     926          $this->assertEquals(array(), $return);
     927  
     928          $this->assertEquals(1, $DB->count_records('message_conversation_actions'));
     929      }
     930  
     931      /**
     932       * Test muting a conversation with messaging disabled.
     933       */
     934      public function test_mute_conversations_messaging_disabled() {
     935          global $CFG;
     936  
     937          $this->resetAfterTest();
     938  
     939          // Create some skeleton data just so we can call the WS.
     940          $user1 = self::getDataGenerator()->create_user();
     941          $user2 = self::getDataGenerator()->create_user();
     942  
     943          $conversation = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
     944              [$user1->id, $user2->id]);
     945  
     946          $this->setUser($user1);
     947  
     948          // Disable messaging.
     949          $CFG->messaging = 0;
     950  
     951          // Ensure an exception is thrown.
     952          $this->expectException('moodle_exception');
     953          core_message_external::mute_conversations($user1->id, [$conversation->id]);
     954      }
     955  
     956      /**
     957       * Test muting a conversation with no permission.
     958       */
     959      public function test_mute_conversations_no_permission() {
     960          $this->resetAfterTest();
     961  
     962          // Create some skeleton data just so we can call the WS.
     963          $user1 = self::getDataGenerator()->create_user();
     964          $user2 = self::getDataGenerator()->create_user();
     965          $user3 = self::getDataGenerator()->create_user();
     966  
     967          $conversation = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
     968              [$user1->id, $user2->id]);
     969  
     970          $this->setUser($user3);
     971  
     972          // Ensure an exception is thrown.
     973          $this->expectException('required_capability_exception');
     974          core_message_external::mute_conversations($user1->id, [$conversation->id]);
     975      }
     976  
     977      /**
     978       * Test unmuting conversations.
     979       */
     980      public function test_unmute_conversations() {
     981          global $DB;
     982  
     983          $this->resetAfterTest(true);
     984  
     985          $user1 = self::getDataGenerator()->create_user();
     986          $user2 = self::getDataGenerator()->create_user();
     987  
     988          $conversation = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
     989              [$user1->id, $user2->id]);
     990  
     991          $this->setUser($user1);
     992  
     993          // Mute the conversation.
     994          \core_message\api::mute_conversation($user1->id, $conversation->id);
     995  
     996          // Unmuting a conversation.
     997          $return = core_message_external::unmute_conversations($user1->id, [$conversation->id]);
     998          $return = external_api::clean_returnvalue(core_message_external::unmute_conversations_returns(), $return);
     999          $this->assertEquals(array(), $return);
    1000  
    1001          $this->assertEquals(0, $DB->count_records('message_conversation_actions'));
    1002  
    1003          // Unmuting a conversation which is already unmuted.
    1004          $return = core_message_external::unmute_conversations($user1->id, [$conversation->id]);
    1005          $return = external_api::clean_returnvalue(core_message_external::unmute_conversations_returns(), $return);
    1006          $this->assertEquals(array(), $return);
    1007  
    1008          $this->assertEquals(0, $DB->count_records('message_conversation_actions'));
    1009      }
    1010  
    1011      /**
    1012       * Test unmuting a conversation with messaging disabled.
    1013       */
    1014      public function test_unmute_conversation_messaging_disabled() {
    1015          global $CFG;
    1016  
    1017          $this->resetAfterTest();
    1018  
    1019          // Create some skeleton data just so we can call the WS.
    1020          $user1 = self::getDataGenerator()->create_user();
    1021          $user2 = self::getDataGenerator()->create_user();
    1022  
    1023          $conversation = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
    1024              [$user1->id, $user2->id]);
    1025  
    1026          $this->setUser($user1);
    1027  
    1028          // Disable messaging.
    1029          $CFG->messaging = 0;
    1030  
    1031          // Ensure an exception is thrown.
    1032          $this->expectException('moodle_exception');
    1033          core_message_external::unmute_conversations($user1->id, [$user2->id]);
    1034      }
    1035  
    1036      /**
    1037       * Test unmuting a conversation with no permission.
    1038       */
    1039      public function test_unmute_conversation_no_permission() {
    1040          $this->resetAfterTest();
    1041  
    1042          // Create some skeleton data just so we can call the WS.
    1043          $user1 = self::getDataGenerator()->create_user();
    1044          $user2 = self::getDataGenerator()->create_user();
    1045          $user3 = self::getDataGenerator()->create_user();
    1046  
    1047          $conversation = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
    1048              [$user1->id, $user2->id]);
    1049  
    1050          $this->setUser($user3);
    1051  
    1052          // Ensure an exception is thrown.
    1053          $this->expectException('required_capability_exception');
    1054          core_message_external::unmute_conversations($user1->id, [$conversation->id]);
    1055      }
    1056  
    1057      /**
    1058       * Test blocking a user.
    1059       */
    1060      public function test_block_user() {
    1061          global $DB;
    1062  
    1063          $this->resetAfterTest(true);
    1064  
    1065          $user1 = self::getDataGenerator()->create_user();
    1066          $user2 = self::getDataGenerator()->create_user();
    1067  
    1068          $this->setUser($user1);
    1069  
    1070          // Blocking a user.
    1071          $return = core_message_external::block_user($user1->id, $user2->id);
    1072          $return = external_api::clean_returnvalue(core_message_external::block_user_returns(), $return);
    1073          $this->assertEquals(array(), $return);
    1074  
    1075          // Get list of blocked users.
    1076          $record = $DB->get_record('message_users_blocked', []);
    1077  
    1078          $this->assertEquals($user1->id, $record->userid);
    1079          $this->assertEquals($user2->id, $record->blockeduserid);
    1080  
    1081          // Blocking a user who is already blocked.
    1082          $return = core_message_external::block_user($user1->id, $user2->id);
    1083          $return = external_api::clean_returnvalue(core_message_external::block_user_returns(), $return);
    1084          $this->assertEquals(array(), $return);
    1085  
    1086          $this->assertEquals(1, $DB->count_records('message_users_blocked'));
    1087      }
    1088  
    1089      /**
    1090       * Test blocking a user.
    1091       */
    1092      public function test_block_user_when_ineffective() {
    1093          global $DB;
    1094  
    1095          $this->resetAfterTest(true);
    1096  
    1097          $user1 = self::getDataGenerator()->create_user();
    1098          $user2 = self::getDataGenerator()->create_user();
    1099  
    1100          $this->setUser($user1);
    1101  
    1102          $authenticateduser = $DB->get_record('role', array('shortname' => 'user'));
    1103          assign_capability('moodle/site:messageanyuser', CAP_ALLOW, $authenticateduser->id, context_system::instance(), true);
    1104  
    1105          // Blocking a user.
    1106          $return = core_message_external::block_user($user1->id, $user2->id);
    1107          $return = external_api::clean_returnvalue(core_message_external::block_user_returns(), $return);
    1108          $this->assertEquals(array(), $return);
    1109  
    1110          $this->assertEquals(0, $DB->count_records('message_users_blocked'));
    1111      }
    1112  
    1113      /**
    1114       * Test blocking a user with messaging disabled.
    1115       */
    1116      public function test_block_user_messaging_disabled() {
    1117          global $CFG;
    1118  
    1119          $this->resetAfterTest();
    1120  
    1121          // Create some skeleton data just so we can call the WS.
    1122          $user1 = self::getDataGenerator()->create_user();
    1123          $user2 = self::getDataGenerator()->create_user();
    1124  
    1125          $this->setUser($user1);
    1126  
    1127          // Disable messaging.
    1128          $CFG->messaging = 0;
    1129  
    1130          // Ensure an exception is thrown.
    1131          $this->expectException('moodle_exception');
    1132          core_message_external::block_user($user1->id, $user2->id);
    1133      }
    1134  
    1135      /**
    1136       * Test blocking a user with no permission.
    1137       */
    1138      public function test_block_user_no_permission() {
    1139          $this->resetAfterTest();
    1140  
    1141          // Create some skeleton data just so we can call the WS.
    1142          $user1 = self::getDataGenerator()->create_user();
    1143          $user2 = self::getDataGenerator()->create_user();
    1144          $user3 = self::getDataGenerator()->create_user();
    1145  
    1146          $this->setUser($user3);
    1147  
    1148          // Ensure an exception is thrown.
    1149          $this->expectException('required_capability_exception');
    1150          core_message_external::block_user($user1->id, $user2->id);
    1151      }
    1152  
    1153      /**
    1154       * Test unblocking a user.
    1155       */
    1156      public function test_unblock_user() {
    1157          global $DB;
    1158  
    1159          $this->resetAfterTest(true);
    1160  
    1161          $user1 = self::getDataGenerator()->create_user();
    1162          $user2 = self::getDataGenerator()->create_user();
    1163  
    1164          $this->setUser($user1);
    1165  
    1166          // Block the user.
    1167          \core_message\api::block_user($user1->id, $user2->id);
    1168  
    1169          // Unblocking a user.
    1170          $return = core_message_external::unblock_user($user1->id, $user2->id);
    1171          $return = external_api::clean_returnvalue(core_message_external::unblock_user_returns(), $return);
    1172          $this->assertEquals(array(), $return);
    1173  
    1174          $this->assertEquals(0, $DB->count_records('message_users_blocked'));
    1175  
    1176          // Unblocking a user who is already unblocked.
    1177          $return = core_message_external::unblock_user($user1->id, $user2->id);
    1178          $return = external_api::clean_returnvalue(core_message_external::unblock_user_returns(), $return);
    1179          $this->assertEquals(array(), $return);
    1180  
    1181          $this->assertEquals(0, $DB->count_records('message_users_blocked'));
    1182      }
    1183  
    1184      /**
    1185       * Test unblocking a user with messaging disabled.
    1186       */
    1187      public function test_unblock_user_messaging_disabled() {
    1188          global $CFG;
    1189  
    1190          $this->resetAfterTest();
    1191  
    1192          // Create some skeleton data just so we can call the WS.
    1193          $user1 = self::getDataGenerator()->create_user();
    1194          $user2 = self::getDataGenerator()->create_user();
    1195  
    1196          $this->setUser($user1);
    1197  
    1198          // Disable messaging.
    1199          $CFG->messaging = 0;
    1200  
    1201          // Ensure an exception is thrown.
    1202          $this->expectException('moodle_exception');
    1203          core_message_external::unblock_user($user1->id, $user2->id);
    1204      }
    1205  
    1206      /**
    1207       * Test unblocking a user with no permission.
    1208       */
    1209      public function test_unblock_user_no_permission() {
    1210          $this->resetAfterTest();
    1211  
    1212          // Create some skeleton data just so we can call the WS.
    1213          $user1 = self::getDataGenerator()->create_user();
    1214          $user2 = self::getDataGenerator()->create_user();
    1215          $user3 = self::getDataGenerator()->create_user();
    1216  
    1217          $this->setUser($user3);
    1218  
    1219          // Ensure an exception is thrown.
    1220          $this->expectException('required_capability_exception');
    1221          core_message_external::unblock_user($user1->id, $user2->id);
    1222      }
    1223  
    1224      /**
    1225       * Test search_contacts.
    1226       */
    1227      public function test_search_contacts() {
    1228          global $DB;
    1229          $this->resetAfterTest(true);
    1230  
    1231          $course1 = $this->getDataGenerator()->create_course();
    1232          $course2 = $this->getDataGenerator()->create_course();
    1233  
    1234          $user1 = new stdClass();
    1235          $user1->firstname = 'X';
    1236          $user1->lastname = 'X';
    1237          $user1 = $this->getDataGenerator()->create_user($user1);
    1238          $this->getDataGenerator()->enrol_user($user1->id, $course1->id);
    1239          $this->getDataGenerator()->enrol_user($user1->id, $course2->id);
    1240  
    1241          $user2 = new stdClass();
    1242          $user2->firstname = 'Eric';
    1243          $user2->lastname = 'Cartman';
    1244          $user2 = self::getDataGenerator()->create_user($user2);
    1245          $user3 = new stdClass();
    1246          $user3->firstname = 'Stan';
    1247          $user3->lastname = 'Marsh';
    1248          $user3 = self::getDataGenerator()->create_user($user3);
    1249          self::getDataGenerator()->enrol_user($user3->id, $course1->id);
    1250          $user4 = new stdClass();
    1251          $user4->firstname = 'Kyle';
    1252          $user4->lastname = 'Broflovski';
    1253          $user4 = self::getDataGenerator()->create_user($user4);
    1254          $user5 = new stdClass();
    1255          $user5->firstname = 'Kenny';
    1256          $user5->lastname = 'McCormick';
    1257          $user5 = self::getDataGenerator()->create_user($user5);
    1258          self::getDataGenerator()->enrol_user($user5->id, $course2->id);
    1259  
    1260          $this->setUser($user1);
    1261  
    1262          $results = core_message_external::search_contacts('r');
    1263          $results = external_api::clean_returnvalue(core_message_external::search_contacts_returns(), $results);
    1264          $this->assertCount(5, $results); // Users 2 through 5 + admin
    1265  
    1266          $results = core_message_external::search_contacts('r', true);
    1267          $results = external_api::clean_returnvalue(core_message_external::search_contacts_returns(), $results);
    1268          $this->assertCount(2, $results);
    1269  
    1270          $results = core_message_external::search_contacts('Kyle', false);
    1271          $results = external_api::clean_returnvalue(core_message_external::search_contacts_returns(), $results);
    1272          $this->assertCount(1, $results);
    1273          $result = reset($results);
    1274          $this->assertEquals($user4->id, $result['id']);
    1275  
    1276          $results = core_message_external::search_contacts('y', false);
    1277          $results = external_api::clean_returnvalue(core_message_external::search_contacts_returns(), $results);
    1278          $this->assertCount(2, $results);
    1279  
    1280          $results = core_message_external::search_contacts('y', true);
    1281          $results = external_api::clean_returnvalue(core_message_external::search_contacts_returns(), $results);
    1282          $this->assertCount(1, $results);
    1283          $result = reset($results);
    1284          $this->assertEquals($user5->id, $result['id']);
    1285  
    1286          // Empty query, will throw an exception.
    1287          $this->expectException(moodle_exception::class);
    1288          $results = core_message_external::search_contacts('');
    1289      }
    1290  
    1291      /**
    1292       * Test get_messages.
    1293       */
    1294      public function test_get_messages() {
    1295          global $CFG, $DB;
    1296          $this->resetAfterTest(true);
    1297  
    1298          $this->preventResetByRollback();
    1299          // This mark the messages as read!.
    1300          $sink = $this->redirectMessages();
    1301  
    1302          $user1 = self::getDataGenerator()->create_user();
    1303          $user2 = self::getDataGenerator()->create_user();
    1304          $user3 = self::getDataGenerator()->create_user();
    1305  
    1306          $course = self::getDataGenerator()->create_course();
    1307  
    1308          // Send a message from one user to another.
    1309          message_post_message($user1, $user2, 'some random text 1', FORMAT_MOODLE);
    1310          message_post_message($user1, $user3, 'some random text 2', FORMAT_MOODLE);
    1311          message_post_message($user2, $user3, 'some random text 3', FORMAT_MOODLE);
    1312          message_post_message($user3, $user2, 'some random text 4', FORMAT_MOODLE);
    1313          message_post_message($user3, $user1, 'some random text 5', FORMAT_MOODLE);
    1314  
    1315          $this->setUser($user1);
    1316          // Get read conversations from user1 to user2.
    1317          $messages = core_message_external::get_messages($user2->id, $user1->id, 'conversations', true, true, 0, 0);
    1318          $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
    1319          $this->assertCount(1, $messages['messages']);
    1320  
    1321          // Delete the message.
    1322          $message = array_shift($messages['messages']);
    1323          \core_message\api::delete_message($user1->id, $message['id']);
    1324  
    1325          $messages = core_message_external::get_messages($user2->id, $user1->id, 'conversations', true, true, 0, 0);
    1326          $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
    1327          $this->assertCount(0, $messages['messages']);
    1328  
    1329          // Get unread conversations from user1 to user2.
    1330          $messages = core_message_external::get_messages($user2->id, $user1->id, 'conversations', false, true, 0, 0);
    1331          $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
    1332          $this->assertCount(0, $messages['messages']);
    1333  
    1334          // Get read messages send from user1.
    1335          $messages = core_message_external::get_messages(0, $user1->id, 'conversations', true, true, 0, 0);
    1336          $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
    1337          $this->assertCount(1, $messages['messages']);
    1338  
    1339          $this->setUser($user2);
    1340          // Get read conversations from any user to user2.
    1341          $messages = core_message_external::get_messages($user2->id, 0, 'conversations', true, true, 0, 0);
    1342          $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
    1343          $this->assertCount(2, $messages['messages']);
    1344  
    1345          // Conversations from user3 to user2.
    1346          $messages = core_message_external::get_messages($user2->id, $user3->id, 'conversations', true, true, 0, 0);
    1347          $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
    1348          $this->assertCount(1, $messages['messages']);
    1349  
    1350          // Delete the message.
    1351          $message = array_shift($messages['messages']);
    1352          \core_message\api::delete_message($user2->id, $message['id']);
    1353  
    1354          $messages = core_message_external::get_messages($user2->id, $user3->id, 'conversations', true, true, 0, 0);
    1355          $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
    1356          $this->assertCount(0, $messages['messages']);
    1357  
    1358          $this->setUser($user3);
    1359          // Get read notifications received by user3.
    1360          $messages = core_message_external::get_messages($user3->id, 0, 'notifications', true, true, 0, 0);
    1361          $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
    1362          $this->assertCount(0, $messages['messages']);
    1363  
    1364          // Now, create some notifications...
    1365          // We are creating fake notifications but based on real ones.
    1366  
    1367          // This one comes from a disabled plugin's provider and therefore is not sent.
    1368          $eventdata = new \core\message\message();
    1369          $eventdata->courseid          = $course->id;
    1370          $eventdata->notification      = 1;
    1371          $eventdata->modulename        = 'moodle';
    1372          $eventdata->component         = 'enrol_paypal';
    1373          $eventdata->name              = 'paypal_enrolment';
    1374          $eventdata->userfrom          = get_admin();
    1375          $eventdata->userto            = $user1;
    1376          $eventdata->subject           = "Moodle: PayPal payment";
    1377          $eventdata->fullmessage       = "Your PayPal payment is pending.";
    1378          $eventdata->fullmessageformat = FORMAT_PLAIN;
    1379          $eventdata->fullmessagehtml   = '';
    1380          $eventdata->smallmessage      = '';
    1381          message_send($eventdata);
    1382          $this->assertDebuggingCalled('Attempt to send msg from a provider enrol_paypal/paypal_enrolment '.
    1383              'that is inactive or not allowed for the user id='.$user1->id);
    1384  
    1385          // This one omits notification = 1.
    1386          $message = new \core\message\message();
    1387          $message->courseid          = $course->id;
    1388          $message->component         = 'enrol_manual';
    1389          $message->name              = 'expiry_notification';
    1390          $message->userfrom          = $user2;
    1391          $message->userto            = $user1;
    1392          $message->subject           = 'Test: This is not a notification but otherwise is valid';
    1393          $message->fullmessage       = 'Test: Full message';
    1394          $message->fullmessageformat = FORMAT_MARKDOWN;
    1395          $message->fullmessagehtml   = markdown_to_html($message->fullmessage);
    1396          $message->smallmessage      = $message->subject;
    1397          $message->contexturlname    = $course->fullname;
    1398          $message->contexturl        = (string)new moodle_url('/course/view.php', array('id' => $course->id));
    1399          message_send($message);
    1400  
    1401          $message = new \core\message\message();
    1402          $message->courseid          = $course->id;
    1403          $message->notification      = 1;
    1404          $message->component         = 'enrol_manual';
    1405          $message->name              = 'expiry_notification';
    1406          $message->userfrom          = $user2;
    1407          $message->userto            = $user1;
    1408          $message->subject           = 'Enrolment expired';
    1409          $message->fullmessage       = 'Enrolment expired blah blah blah';
    1410          $message->fullmessageformat = FORMAT_MARKDOWN;
    1411          $message->fullmessagehtml   = markdown_to_html($message->fullmessage);
    1412          $message->smallmessage      = $message->subject;
    1413          $message->contexturlname    = $course->fullname;
    1414          $message->contexturl        = (string)new moodle_url('/course/view.php', array('id' => $course->id));
    1415          message_send($message);
    1416  
    1417          $userfrom = core_user::get_noreply_user();
    1418          $userfrom->maildisplay = true;
    1419          $eventdata = new \core\message\message();
    1420          $eventdata->courseid          = $course->id;
    1421          $eventdata->component         = 'moodle';
    1422          $eventdata->name              = 'badgecreatornotice';
    1423          $eventdata->userfrom          = $userfrom;
    1424          $eventdata->userto            = $user1;
    1425          $eventdata->notification      = 1;
    1426          $eventdata->subject           = 'New badge';
    1427          $eventdata->fullmessage       = format_text_email($eventdata->subject, FORMAT_HTML);
    1428          $eventdata->fullmessageformat = FORMAT_PLAIN;
    1429          $eventdata->fullmessagehtml   = $eventdata->subject;
    1430          $eventdata->smallmessage      = $eventdata->subject;
    1431          message_send($eventdata);
    1432  
    1433          $eventdata = new \core\message\message();
    1434          $eventdata->courseid         = $course->id;
    1435          $eventdata->name             = 'submission';
    1436          $eventdata->component        = 'mod_feedback';
    1437          $eventdata->userfrom         = $user1;
    1438          $eventdata->userto           = $user2;
    1439          $eventdata->subject          = 'Feedback submitted';
    1440          $eventdata->fullmessage      = 'Feedback submitted from an user';
    1441          $eventdata->fullmessageformat = FORMAT_PLAIN;
    1442          $eventdata->fullmessagehtml  = '<strong>Feedback submitted</strong>';
    1443          $eventdata->smallmessage     = '';
    1444          $eventdata->customdata         = ['datakey' => 'data'];
    1445          message_send($eventdata);
    1446  
    1447          $this->setUser($user1);
    1448          // Get read notifications from any user to user1.
    1449          $messages = core_message_external::get_messages($user1->id, 0, 'notifications', true, true, 0, 0);
    1450          $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
    1451          $this->assertCount(3, $messages['messages']);
    1452  
    1453          // Get one read notifications from any user to user1.
    1454          $messages = core_message_external::get_messages($user1->id, 0, 'notifications', true, true, 0, 1);
    1455          $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
    1456          $this->assertCount(1, $messages['messages']);
    1457  
    1458          // Get unread notifications from any user to user1.
    1459          $messages = core_message_external::get_messages($user1->id, 0, 'notifications', false, true, 0, 0);
    1460          $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
    1461          $this->assertCount(0, $messages['messages']);
    1462  
    1463          // Get read both type of messages from any user to user1.
    1464          $messages = core_message_external::get_messages($user1->id, 0, 'both', true, true, 0, 0);
    1465          $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
    1466          $this->assertCount(4, $messages['messages']);
    1467  
    1468          // Get read notifications from no-reply-user to user1.
    1469          $messages = core_message_external::get_messages($user1->id, $userfrom->id, 'notifications', true, true, 0, 0);
    1470          $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
    1471          $this->assertCount(1, $messages['messages']);
    1472  
    1473          // Get notifications send by user1 to any user.
    1474          $messages = core_message_external::get_messages(0, $user1->id, 'notifications', true, true, 0, 0);
    1475          $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
    1476          $this->assertCount(1, $messages['messages']);
    1477          // Check we receive custom data as a unserialisable json.
    1478          $this->assertObjectHasAttribute('datakey', json_decode($messages['messages'][0]['customdata']));
    1479          $this->assertEquals('mod_feedback', $messages['messages'][0]['component']);
    1480          $this->assertEquals('submission', $messages['messages'][0]['eventtype']);
    1481  
    1482          // Test warnings.
    1483          $CFG->messaging = 0;
    1484  
    1485          $messages = core_message_external::get_messages(0, $user1->id, 'both', true, true, 0, 0);
    1486          $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
    1487          $this->assertCount(1, $messages['warnings']);
    1488  
    1489          // Test exceptions.
    1490  
    1491          // Messaging disabled.
    1492          try {
    1493              $messages = core_message_external::get_messages(0, $user1->id, 'conversations', true, true, 0, 0);
    1494              $this->fail('Exception expected due messaging disabled.');
    1495          } catch (moodle_exception $e) {
    1496              $this->assertEquals('disabled', $e->errorcode);
    1497          }
    1498  
    1499          $CFG->messaging = 1;
    1500  
    1501          // Invalid users.
    1502          try {
    1503              $messages = core_message_external::get_messages(0, 0, 'conversations', true, true, 0, 0);
    1504              $this->fail('Exception expected due invalid users.');
    1505          } catch (moodle_exception $e) {
    1506              $this->assertEquals('accessdenied', $e->errorcode);
    1507          }
    1508  
    1509          // Invalid user ids.
    1510          try {
    1511              $messages = core_message_external::get_messages(2500, 0, 'conversations', true, true, 0, 0);
    1512              $this->fail('Exception expected due invalid users.');
    1513          } catch (moodle_exception $e) {
    1514              $this->assertEquals('invaliduser', $e->errorcode);
    1515          }
    1516  
    1517          // Invalid users (permissions).
    1518          $this->setUser($user2);
    1519          try {
    1520              $messages = core_message_external::get_messages(0, $user1->id, 'conversations', true, true, 0, 0);
    1521              $this->fail('Exception expected due invalid user.');
    1522          } catch (moodle_exception $e) {
    1523              $this->assertEquals('accessdenied', $e->errorcode);
    1524          }
    1525  
    1526      }
    1527  
    1528      /**
    1529       * Test get_messages where we want all messages from a user, sent to any user.
    1530       */
    1531      public function test_get_messages_useridto_all() {
    1532          $this->resetAfterTest(true);
    1533  
    1534          $user1 = self::getDataGenerator()->create_user();
    1535          $user2 = self::getDataGenerator()->create_user();
    1536          $user3 = self::getDataGenerator()->create_user();
    1537  
    1538          $this->setUser($user1);
    1539  
    1540          // Send a message from user 1 to two other users.
    1541          $this->send_message($user1, $user2, 'some random text 1', 0, 1);
    1542          $this->send_message($user1, $user3, 'some random text 2', 0, 2);
    1543  
    1544          // Get messages sent from user 1.
    1545          $messages = core_message_external::get_messages(0, $user1->id, 'conversations', false, false, 0, 0);
    1546          $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
    1547  
    1548          // Confirm the data is correct.
    1549          $messages = $messages['messages'];
    1550          $this->assertCount(2, $messages);
    1551  
    1552          $message1 = array_shift($messages);
    1553          $message2 = array_shift($messages);
    1554  
    1555          $this->assertEquals($user1->id, $message1['useridfrom']);
    1556          $this->assertEquals($user2->id, $message1['useridto']);
    1557  
    1558          $this->assertEquals($user1->id, $message2['useridfrom']);
    1559          $this->assertEquals($user3->id, $message2['useridto']);
    1560      }
    1561  
    1562      /**
    1563       * Test get_messages where we want all messages to a user, sent by any user.
    1564       */
    1565      public function test_get_messages_useridfrom_all() {
    1566          $this->resetAfterTest();
    1567  
    1568          $user1 = self::getDataGenerator()->create_user();
    1569          $user2 = self::getDataGenerator()->create_user();
    1570          $user3 = self::getDataGenerator()->create_user();
    1571  
    1572          $this->setUser($user1);
    1573  
    1574          // Send a message to user 1 from two other users.
    1575          $this->send_message($user2, $user1, 'some random text 1', 0, 1);
    1576          $this->send_message($user3, $user1, 'some random text 2', 0, 2);
    1577  
    1578          // Get messages sent to user 1.
    1579          $messages = core_message_external::get_messages($user1->id, 0, 'conversations', false, false, 0, 0);
    1580          $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
    1581  
    1582          // Confirm the data is correct.
    1583          $messages = $messages['messages'];
    1584          $this->assertCount(2, $messages);
    1585  
    1586          $message1 = array_shift($messages);
    1587          $message2 = array_shift($messages);
    1588  
    1589          $this->assertEquals($user2->id, $message1['useridfrom']);
    1590          $this->assertEquals($user1->id, $message1['useridto']);
    1591  
    1592          $this->assertEquals($user3->id, $message2['useridfrom']);
    1593          $this->assertEquals($user1->id, $message2['useridto']);
    1594      }
    1595  
    1596      /**
    1597       * Test get_blocked_users.
    1598       */
    1599      public function test_get_blocked_users() {
    1600          $this->resetAfterTest(true);
    1601  
    1602          $user1 = self::getDataGenerator()->create_user();
    1603          $userstranger = self::getDataGenerator()->create_user();
    1604          $useroffline1 = self::getDataGenerator()->create_user();
    1605          $useroffline2 = self::getDataGenerator()->create_user();
    1606          $userblocked = self::getDataGenerator()->create_user();
    1607  
    1608          // Login as user1.
    1609          $this->setUser($user1);
    1610  
    1611          \core_message\api::add_contact($user1->id, $useroffline1->id);
    1612          \core_message\api::add_contact($user1->id, $useroffline2->id);
    1613  
    1614          // The userstranger sends a couple of messages to user1.
    1615          $this->send_message($userstranger, $user1, 'Hello there!');
    1616          $this->send_message($userstranger, $user1, 'How you goin?');
    1617  
    1618          // The userblocked sends a message to user1.
    1619          // Note that this user is not blocked at this point.
    1620          $this->send_message($userblocked, $user1, 'Here, have some spam.');
    1621  
    1622          // Retrieve the list of blocked users.
    1623          $this->setUser($user1);
    1624          $blockedusers = core_message_external::get_blocked_users($user1->id);
    1625          $blockedusers = external_api::clean_returnvalue(core_message_external::get_blocked_users_returns(), $blockedusers);
    1626          $this->assertCount(0, $blockedusers['users']);
    1627  
    1628          // Block the $userblocked and retrieve again the list.
    1629          \core_message\api::block_user($user1->id, $userblocked->id);
    1630          $blockedusers = core_message_external::get_blocked_users($user1->id);
    1631          $blockedusers = external_api::clean_returnvalue(core_message_external::get_blocked_users_returns(), $blockedusers);
    1632          $this->assertCount(1, $blockedusers['users']);
    1633  
    1634          // Remove the $userblocked and check that the list now is empty.
    1635          delete_user($userblocked);
    1636          $blockedusers = core_message_external::get_blocked_users($user1->id);
    1637          $blockedusers = external_api::clean_returnvalue(core_message_external::get_blocked_users_returns(), $blockedusers);
    1638          $this->assertCount(0, $blockedusers['users']);
    1639      }
    1640  
    1641      /**
    1642       * Test mark_message_read.
    1643       */
    1644      public function test_mark_message_read() {
    1645          $this->resetAfterTest(true);
    1646  
    1647          $user1 = self::getDataGenerator()->create_user();
    1648          $user2 = self::getDataGenerator()->create_user();
    1649          $user3 = self::getDataGenerator()->create_user();
    1650  
    1651          // Login as user1.
    1652          $this->setUser($user1);
    1653          \core_message\api::add_contact($user1->id, $user2->id);
    1654          \core_message\api::add_contact($user1->id, $user3->id);
    1655  
    1656          // The user2 sends a couple of messages to user1.
    1657          $this->send_message($user2, $user1, 'Hello there!');
    1658          $this->send_message($user2, $user1, 'How you goin?');
    1659          $this->send_message($user3, $user1, 'How you goin?');
    1660          $this->send_message($user3, $user2, 'How you goin?');
    1661  
    1662          // Retrieve all messages sent by user2 (they are currently unread).
    1663          $lastmessages = message_get_messages($user1->id, $user2->id, 0, false);
    1664  
    1665          $messageids = array();
    1666          foreach ($lastmessages as $m) {
    1667              $messageid = core_message_external::mark_message_read($m->id, time());
    1668              $messageids[] = external_api::clean_returnvalue(core_message_external::mark_message_read_returns(), $messageid);
    1669          }
    1670  
    1671          // Retrieve all messages sent (they are currently read).
    1672          $lastmessages = message_get_messages($user1->id, $user2->id, 0, true);
    1673          $this->assertCount(2, $lastmessages);
    1674          $this->assertArrayHasKey($messageids[0]['messageid'], $lastmessages);
    1675          $this->assertArrayHasKey($messageids[1]['messageid'], $lastmessages);
    1676  
    1677          // Retrieve all messages sent by any user (that are currently unread).
    1678          $lastmessages = message_get_messages($user1->id, 0, 0, false);
    1679          $this->assertCount(1, $lastmessages);
    1680  
    1681          // Invalid message ids.
    1682          try {
    1683              $messageid = core_message_external::mark_message_read(1337, time());
    1684              $this->fail('Exception expected due invalid messageid.');
    1685          } catch (dml_missing_record_exception $e) {
    1686              $this->assertEquals('invalidrecordunknown', $e->errorcode);
    1687          }
    1688  
    1689          // A message to a different user.
    1690          $lastmessages = message_get_messages($user2->id, $user3->id, 0, false);
    1691          $messageid = array_pop($lastmessages)->id;
    1692          try {
    1693              $messageid = core_message_external::mark_message_read($messageid, time());
    1694              $this->fail('Exception expected due invalid messageid.');
    1695          } catch (invalid_parameter_exception $e) {
    1696              $this->assertEquals('invalidparameter', $e->errorcode);
    1697          }
    1698      }
    1699  
    1700      /**
    1701       * Test mark_notification_read.
    1702       */
    1703      public function test_mark_notification_read() {
    1704          $this->resetAfterTest(true);
    1705  
    1706          $user1 = self::getDataGenerator()->create_user();
    1707          $user2 = self::getDataGenerator()->create_user();
    1708          $user3 = self::getDataGenerator()->create_user();
    1709  
    1710          // Login as user1.
    1711          $this->setUser($user1);
    1712          \core_message\api::add_contact($user1->id, $user2->id);
    1713          \core_message\api::add_contact($user1->id, $user3->id);
    1714  
    1715          // The user2 sends a couple of notifications to user1.
    1716          $this->send_message($user2, $user1, 'Hello there!', 1);
    1717          $this->send_message($user2, $user1, 'How you goin?', 1);
    1718          $this->send_message($user3, $user1, 'How you goin?', 1);
    1719          $this->send_message($user3, $user2, 'How you goin?', 1);
    1720  
    1721          // Retrieve all notifications sent by user2 (they are currently unread).
    1722          $lastnotifications = message_get_messages($user1->id, $user2->id, 1, false);
    1723  
    1724          $notificationids = array();
    1725          foreach ($lastnotifications as $n) {
    1726              $notificationid = core_message_external::mark_notification_read($n->id, time());
    1727              $notificationids[] = external_api::clean_returnvalue(core_message_external::mark_notification_read_returns(),
    1728                  $notificationid);
    1729          }
    1730  
    1731          // Retrieve all notifications sent (they are currently read).
    1732          $lastnotifications = message_get_messages($user1->id, $user2->id, 1, true);
    1733          $this->assertCount(2, $lastnotifications);
    1734          $this->assertArrayHasKey($notificationids[1]['notificationid'], $lastnotifications);
    1735          $this->assertArrayHasKey($notificationids[0]['notificationid'], $lastnotifications);
    1736  
    1737          // Retrieve all notifications sent by any user (that are currently unread).
    1738          $lastnotifications = message_get_messages($user1->id, 0, 1, false);
    1739          $this->assertCount(1, $lastnotifications);
    1740  
    1741          // Invalid notification ids.
    1742          try {
    1743              $notificationid = core_message_external::mark_notification_read(1337, time());
    1744              $this->fail('Exception expected due invalid notificationid.');
    1745          } catch (dml_missing_record_exception $e) {
    1746              $this->assertEquals('invalidrecord', $e->errorcode);
    1747          }
    1748  
    1749          // A notification to a different user.
    1750          $lastnotifications = message_get_messages($user2->id, $user3->id, 1, false);
    1751          $notificationid = array_pop($lastnotifications)->id;
    1752          try {
    1753              $notificationid = core_message_external::mark_notification_read($notificationid, time());
    1754              $this->fail('Exception expected due invalid notificationid.');
    1755          } catch (invalid_parameter_exception $e) {
    1756              $this->assertEquals('invalidparameter', $e->errorcode);
    1757          }
    1758      }
    1759  
    1760      /**
    1761       * Test delete_message.
    1762       */
    1763      public function test_delete_message() {
    1764          global $DB;
    1765          $this->resetAfterTest(true);
    1766  
    1767          $user1 = self::getDataGenerator()->create_user();
    1768          $user2 = self::getDataGenerator()->create_user();
    1769          $user3 = self::getDataGenerator()->create_user();
    1770          $user4 = self::getDataGenerator()->create_user();
    1771  
    1772          // Login as user1.
    1773          $this->setUser($user1);
    1774          \core_message\api::add_contact($user1->id, $user2->id);
    1775          \core_message\api::add_contact($user1->id, $user3->id);
    1776  
    1777          // User user1 does not interchange messages with user3.
    1778          $m1to2 = message_post_message($user1, $user2, 'some random text 1', FORMAT_MOODLE);
    1779          $m2to3 = message_post_message($user2, $user3, 'some random text 3', FORMAT_MOODLE);
    1780          $m3to2 = message_post_message($user3, $user2, 'some random text 4', FORMAT_MOODLE);
    1781          $m3to4 = message_post_message($user3, $user4, 'some random text 4', FORMAT_MOODLE);
    1782  
    1783          // Retrieve all messages sent by user2 (they are currently unread).
    1784          $lastmessages = message_get_messages($user1->id, $user2->id, 0, false);
    1785  
    1786          // Delete a message not read, as a user from.
    1787          $result = core_message_external::delete_message($m1to2, $user1->id, false);
    1788          $result = external_api::clean_returnvalue(core_message_external::delete_message_returns(), $result);
    1789          $this->assertTrue($result['status']);
    1790          $this->assertCount(0, $result['warnings']);
    1791          $mua = $DB->get_record('message_user_actions', array('messageid' => $m1to2, 'userid' => $user1->id));
    1792          $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua->action);
    1793  
    1794          // Try to delete the same message again.
    1795          $result = core_message_external::delete_message($m1to2, $user1->id, false);
    1796          $result = external_api::clean_returnvalue(core_message_external::delete_message_returns(), $result);
    1797          $this->assertFalse($result['status']);
    1798  
    1799          // Try to delete a message that does not belong to me.
    1800          try {
    1801              $messageid = core_message_external::delete_message($m2to3, $user3->id, false);
    1802              $this->fail('Exception expected due invalid messageid.');
    1803          } catch (moodle_exception $e) {
    1804              $this->assertEquals('You do not have permission to delete this message', $e->errorcode);
    1805          }
    1806  
    1807          $this->setUser($user3);
    1808          // Delete a message not read, as a user to.
    1809          $result = core_message_external::delete_message($m2to3, $user3->id, false);
    1810          $result = external_api::clean_returnvalue(core_message_external::delete_message_returns(), $result);
    1811          $this->assertTrue($result['status']);
    1812          $this->assertCount(0, $result['warnings']);
    1813          $this->assertTrue($DB->record_exists('message_user_actions', array('messageid' => $m2to3, 'userid' => $user3->id,
    1814              'action' => \core_message\api::MESSAGE_ACTION_DELETED)));
    1815  
    1816          // Delete a message read.
    1817          $message = $DB->get_record('messages', ['id' => $m3to2]);
    1818          \core_message\api::mark_message_as_read($user3->id, $message, time());
    1819          $result = core_message_external::delete_message($m3to2, $user3->id);
    1820          $result = external_api::clean_returnvalue(core_message_external::delete_message_returns(), $result);
    1821          $this->assertTrue($result['status']);
    1822          $this->assertCount(0, $result['warnings']);
    1823          $this->assertTrue($DB->record_exists('message_user_actions', array('messageid' => $m3to2, 'userid' => $user3->id,
    1824              'action' => \core_message\api::MESSAGE_ACTION_DELETED)));
    1825  
    1826          // Invalid message ids.
    1827          try {
    1828              $result = core_message_external::delete_message(-1, $user1->id);
    1829              $this->fail('Exception expected due invalid messageid.');
    1830          } catch (dml_missing_record_exception $e) {
    1831              $this->assertEquals('invalidrecord', $e->errorcode);
    1832          }
    1833  
    1834          // Invalid user.
    1835          try {
    1836              $result = core_message_external::delete_message($m1to2, -1, false);
    1837              $this->fail('Exception expected due invalid user.');
    1838          } catch (moodle_exception $e) {
    1839              $this->assertEquals('invaliduser', $e->errorcode);
    1840          }
    1841  
    1842          // Not active user.
    1843          delete_user($user2);
    1844          try {
    1845              $result = core_message_external::delete_message($m1to2, $user2->id, false);
    1846              $this->fail('Exception expected due invalid user.');
    1847          } catch (moodle_exception $e) {
    1848              $this->assertEquals('userdeleted', $e->errorcode);
    1849          }
    1850  
    1851          // Now, as an admin, try to delete any message.
    1852          $this->setAdminUser();
    1853          $result = core_message_external::delete_message($m3to4, $user4->id, false);
    1854          $result = external_api::clean_returnvalue(core_message_external::delete_message_returns(), $result);
    1855          $this->assertTrue($result['status']);
    1856          $this->assertCount(0, $result['warnings']);
    1857          $this->assertTrue($DB->record_exists('message_user_actions', array('messageid' => $m3to4, 'userid' => $user4->id,
    1858              'action' => \core_message\api::MESSAGE_ACTION_DELETED)));
    1859  
    1860      }
    1861  
    1862      public function test_mark_all_notifications_as_read_invalid_user_exception() {
    1863          $this->resetAfterTest(true);
    1864  
    1865          $this->expectException('moodle_exception');
    1866          core_message_external::mark_all_notifications_as_read(-2132131, 0);
    1867      }
    1868  
    1869      public function test_mark_all_notifications_as_read_access_denied_exception() {
    1870          $this->resetAfterTest(true);
    1871  
    1872          $sender = $this->getDataGenerator()->create_user();
    1873          $user = $this->getDataGenerator()->create_user();
    1874  
    1875          $this->setUser($user);
    1876          $this->expectException('moodle_exception');
    1877          core_message_external::mark_all_notifications_as_read($sender->id, 0);
    1878      }
    1879  
    1880      public function test_mark_all_notifications_as_read_missing_from_user_exception() {
    1881          $this->resetAfterTest(true);
    1882  
    1883          $sender = $this->getDataGenerator()->create_user();
    1884  
    1885          $this->setUser($sender);
    1886          $this->expectException('moodle_exception');
    1887          core_message_external::mark_all_notifications_as_read($sender->id, 99999);
    1888      }
    1889  
    1890      public function test_mark_all_notifications_as_read() {
    1891          global $DB;
    1892  
    1893          $this->resetAfterTest(true);
    1894  
    1895          $sender1 = $this->getDataGenerator()->create_user();
    1896          $sender2 = $this->getDataGenerator()->create_user();
    1897          $sender3 = $this->getDataGenerator()->create_user();
    1898          $recipient = $this->getDataGenerator()->create_user();
    1899  
    1900          $this->setUser($recipient);
    1901  
    1902          $this->send_message($sender1, $recipient, 'Notification', 1);
    1903          $this->send_message($sender1, $recipient, 'Notification', 1);
    1904          $this->send_message($sender2, $recipient, 'Notification', 1);
    1905          $this->send_message($sender2, $recipient, 'Notification', 1);
    1906          $this->send_message($sender3, $recipient, 'Notification', 1);
    1907          $this->send_message($sender3, $recipient, 'Notification', 1);
    1908  
    1909          core_message_external::mark_all_notifications_as_read($recipient->id, $sender1->id);
    1910          $readnotifications = $DB->get_records_select('notifications', 'useridto = ? AND timeread IS NOT NULL', [$recipient->id]);
    1911          $unreadnotifications = $DB->get_records_select('notifications', 'useridto = ? AND timeread IS NULL', [$recipient->id]);
    1912  
    1913          $this->assertCount(2, $readnotifications);
    1914          $this->assertCount(4, $unreadnotifications);
    1915  
    1916          core_message_external::mark_all_notifications_as_read($recipient->id, 0);
    1917          $readnotifications = $DB->get_records_select('notifications', 'useridto = ? AND timeread IS NOT NULL', [$recipient->id]);
    1918          $unreadnotifications = $DB->get_records_select('notifications', 'useridto = ? AND timeread IS NULL', [$recipient->id]);
    1919  
    1920          $this->assertCount(6, $readnotifications);
    1921          $this->assertCount(0, $unreadnotifications);
    1922      }
    1923  
    1924      public function test_mark_all_notifications_as_read_time_created_to() {
    1925          global $DB;
    1926  
    1927          $this->resetAfterTest(true);
    1928  
    1929          $sender1 = $this->getDataGenerator()->create_user();
    1930          $sender2 = $this->getDataGenerator()->create_user();
    1931  
    1932          $recipient = $this->getDataGenerator()->create_user();
    1933          $this->setUser($recipient);
    1934  
    1935          // Record messages as sent on one second intervals.
    1936          $time = time();
    1937  
    1938          $this->send_message($sender1, $recipient, 'Message 1', 1, $time);
    1939          $this->send_message($sender2, $recipient, 'Message 2', 1, $time + 1);
    1940          $this->send_message($sender1, $recipient, 'Message 3', 1, $time + 2);
    1941          $this->send_message($sender2, $recipient, 'Message 4', 1, $time + 3);
    1942  
    1943          // Mark notifications sent from sender1 up until the second message; should only mark the first notification as read.
    1944          core_message_external::mark_all_notifications_as_read($recipient->id, $sender1->id, $time + 1);
    1945  
    1946          $params = [$recipient->id];
    1947  
    1948          $this->assertEquals(1, $DB->count_records_select('notifications', 'useridto = ? AND timeread IS NOT NULL', $params));
    1949          $this->assertEquals(3, $DB->count_records_select('notifications', 'useridto = ? AND timeread IS NULL', $params));
    1950  
    1951          // Mark all notifications as read from any sender up to the time the third message was sent.
    1952          core_message_external::mark_all_notifications_as_read($recipient->id, 0, $time + 2);
    1953  
    1954          $this->assertEquals(3, $DB->count_records_select('notifications', 'useridto = ? AND timeread IS NOT NULL', $params));
    1955          $this->assertEquals(1, $DB->count_records_select('notifications', 'useridto = ? AND timeread IS NULL', $params));
    1956  
    1957          // Mark all notifications as read from any sender with a time after all messages were sent.
    1958          core_message_external::mark_all_notifications_as_read($recipient->id, 0, $time + 10);
    1959  
    1960          $this->assertEquals(4, $DB->count_records_select('notifications', 'useridto = ? AND timeread IS NOT NULL', $params));
    1961          $this->assertEquals(0, $DB->count_records_select('notifications', 'useridto = ? AND timeread IS NULL', $params));
    1962      }
    1963  
    1964      /**
    1965       * Test get_user_notification_preferences
    1966       */
    1967      public function test_get_user_notification_preferences() {
    1968          $this->resetAfterTest(true);
    1969  
    1970          $user = self::getDataGenerator()->create_user();
    1971          $this->setUser($user);
    1972  
    1973          // Set a couple of preferences to test.
    1974          set_user_preference('message_provider_mod_assign_assign_notification_loggedin', 'popup', $user);
    1975          set_user_preference('message_provider_mod_assign_assign_notification_loggedoff', 'email', $user);
    1976  
    1977          $prefs = core_message_external::get_user_notification_preferences();
    1978          $prefs = external_api::clean_returnvalue(core_message_external::get_user_notification_preferences_returns(), $prefs);
    1979          // Check processors.
    1980          $this->assertGreaterThanOrEqual(2, count($prefs['preferences']['processors']));
    1981          $this->assertEquals($user->id, $prefs['preferences']['userid']);
    1982  
    1983          // Check components.
    1984          $this->assertGreaterThanOrEqual(8, count($prefs['preferences']['components']));
    1985  
    1986          // Check some preferences that we previously set.
    1987          $found = 0;
    1988          foreach ($prefs['preferences']['components'] as $component) {
    1989              foreach ($component['notifications'] as $prefdata) {
    1990                  if ($prefdata['preferencekey'] != 'message_provider_mod_assign_assign_notification') {
    1991                      continue;
    1992                  }
    1993                  foreach ($prefdata['processors'] as $processor) {
    1994                      if ($processor['name'] == 'popup') {
    1995                          $this->assertTrue($processor['loggedin']['checked']);
    1996                          $found++;
    1997                      } else if ($processor['name'] == 'email') {
    1998                          $this->assertTrue($processor['loggedoff']['checked']);
    1999                          $found++;
    2000                      }
    2001                  }
    2002              }
    2003          }
    2004          $this->assertEquals(2, $found);
    2005      }
    2006  
    2007      /**
    2008       * Test get_user_notification_preferences permissions
    2009       */
    2010      public function test_get_user_notification_preferences_permissions() {
    2011          $this->resetAfterTest(true);
    2012  
    2013          $user = self::getDataGenerator()->create_user();
    2014          $otheruser = self::getDataGenerator()->create_user();
    2015          $this->setUser($user);
    2016  
    2017          $this->expectException('moodle_exception');
    2018          $prefs = core_message_external::get_user_notification_preferences($otheruser->id);
    2019      }
    2020  
    2021      /**
    2022       * Tests searching for users when site-wide messaging is disabled.
    2023       *
    2024       * This test verifies that any contacts are returned, as well as any non-contacts whose profile we can view.
    2025       * If checks this by placing some users in the same course, where default caps would permit a user to view another user's
    2026       * profile.
    2027       */
    2028      public function test_message_search_users_messagingallusers_disabled() {
    2029          global $DB;
    2030          $this->resetAfterTest();
    2031  
    2032          // Create some users.
    2033          $users = [];
    2034          foreach (range(1, 8) as $i) {
    2035              $user = new stdClass();
    2036              $user->firstname = ($i == 4) ? 'User' : 'User search'; // Ensure the fourth user won't match the search term.
    2037              $user->lastname = $i;
    2038              $user = $this->getDataGenerator()->create_user($user);
    2039              $users[$i] = $user;
    2040          }
    2041  
    2042          // Enrol a few users in the same course, but leave them as non-contacts.
    2043          $course1 = $this->getDataGenerator()->create_course();
    2044          $course2 = $this->getDataGenerator()->create_course();
    2045  
    2046          $this->setAdminUser();
    2047          $this->getDataGenerator()->enrol_user($users[1]->id, $course1->id);
    2048          $this->getDataGenerator()->enrol_user($users[6]->id, $course1->id);
    2049          $this->getDataGenerator()->enrol_user($users[7]->id, $course1->id);
    2050  
    2051          // Add some other users as contacts.
    2052          \core_message\api::add_contact($users[1]->id, $users[2]->id);
    2053          \core_message\api::add_contact($users[3]->id, $users[1]->id);
    2054          \core_message\api::add_contact($users[1]->id, $users[4]->id);
    2055  
    2056          // Enrol a user as a teacher in the course, and make the teacher role a course contact role.
    2057          $this->getDataGenerator()->enrol_user($users[8]->id, $course2->id, 'editingteacher');
    2058          $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
    2059          set_config('coursecontact', $teacherrole->id);
    2060  
    2061          // Create individual conversations between some users, one contact and one non-contact.
    2062          \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
    2063              [$users[1]->id, $users[2]->id]);
    2064          \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
    2065              [$users[6]->id, $users[1]->id]);
    2066  
    2067          // Create a group conversation between 4 users, including a contact and a non-contact.
    2068          \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
    2069              [$users[1]->id, $users[2]->id, $users[4]->id, $users[7]->id], 'Project chat');
    2070  
    2071          // Set as the user performing the search.
    2072          $this->setUser($users[1]);
    2073  
    2074          // Perform a search with $CFG->messagingallusers disabled.
    2075          set_config('messagingallusers', 0);
    2076          $result = core_message_external::message_search_users($users[1]->id, 'search');
    2077          $result = external_api::clean_returnvalue(core_message_external::message_search_users_returns(), $result);
    2078  
    2079          // Confirm that we returns contacts and non-contacts.
    2080          $this->assertArrayHasKey('contacts', $result);
    2081          $this->assertArrayHasKey('noncontacts', $result);
    2082          $contacts = $result['contacts'];
    2083          $noncontacts = $result['noncontacts'];
    2084  
    2085          // Check that we retrieved the correct contacts.
    2086          $this->assertCount(2, $contacts);
    2087          $this->assertEquals($users[2]->id, $contacts[0]['id']);
    2088          $this->assertEquals($users[3]->id, $contacts[1]['id']);
    2089  
    2090          // Verify the correct conversations were returned for the contacts.
    2091          $this->assertCount(2, $contacts[0]['conversations']);
    2092          // We can't rely on the ordering of conversations within the results, so sort by id first.
    2093          usort($contacts[0]['conversations'], function($a, $b) {
    2094              return $b['id'] <=> $a['id'];
    2095          });
    2096          $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $contacts[0]['conversations'][0]['type']);
    2097          $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $contacts[0]['conversations'][1]['type']);
    2098  
    2099          $this->assertCount(0, $contacts[1]['conversations']);
    2100  
    2101          // Check that we retrieved the correct non-contacts.
    2102          // When site wide messaging is disabled, we expect to see only those users who we share a course with and whose profiles
    2103          // are visible in that course. This excludes users like course contacts.
    2104          $this->assertCount(3, $noncontacts);
    2105          // Self-conversation first.
    2106          $this->assertEquals($users[1]->id, $noncontacts[0]['id']);
    2107          $this->assertEquals($users[6]->id, $noncontacts[1]['id']);
    2108          $this->assertEquals($users[7]->id, $noncontacts[2]['id']);
    2109  
    2110          // Verify the correct conversations were returned for the non-contacts.
    2111          $this->assertCount(1, $noncontacts[1]['conversations']);
    2112          $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $noncontacts[1]['conversations'][0]['type']);
    2113  
    2114          $this->assertCount(1, $noncontacts[2]['conversations']);
    2115          $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $noncontacts[2]['conversations'][0]['type']);
    2116      }
    2117  
    2118      /**
    2119       * Tests searching for users when site-wide messaging is enabled.
    2120       *
    2121       * This test verifies that any contacts are returned, as well as any non-contacts, regardless of whether the searching user
    2122       * can view their respective profile.
    2123       */
    2124      public function test_message_search_users_messagingallusers_enabled() {
    2125          global $DB;
    2126          $this->resetAfterTest();
    2127  
    2128          // Create some users.
    2129          $users = [];
    2130          foreach (range(1, 9) as $i) {
    2131              $user = new stdClass();
    2132              $user->firstname = ($i == 4) ? 'User' : 'User search'; // Ensure the fourth user won't match the search term.
    2133              $user->lastname = $i;
    2134              $user = $this->getDataGenerator()->create_user($user);
    2135              $users[$i] = $user;
    2136          }
    2137  
    2138          // Enrol a few users in the same course, but leave them as non-contacts.
    2139          $course1 = $this->getDataGenerator()->create_course();
    2140          $course2 = $this->getDataGenerator()->create_course();
    2141  
    2142          $this->setAdminUser();
    2143          $this->getDataGenerator()->enrol_user($users[1]->id, $course1->id);
    2144          $this->getDataGenerator()->enrol_user($users[6]->id, $course1->id);
    2145          $this->getDataGenerator()->enrol_user($users[7]->id, $course1->id);
    2146  
    2147          // Add some other users as contacts.
    2148          \core_message\api::add_contact($users[1]->id, $users[2]->id);
    2149          \core_message\api::add_contact($users[3]->id, $users[1]->id);
    2150          \core_message\api::add_contact($users[1]->id, $users[4]->id);
    2151  
    2152          // Enrol a user as a teacher in the course, and make the teacher role a course contact role.
    2153          $this->getDataGenerator()->enrol_user($users[9]->id, $course2->id, 'editingteacher');
    2154          $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
    2155          set_config('coursecontact', $teacherrole->id);
    2156  
    2157          // Create individual conversations between some users, one contact and one non-contact.
    2158          \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
    2159              [$users[1]->id, $users[2]->id]);
    2160          \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
    2161              [$users[6]->id, $users[1]->id]);
    2162  
    2163          // Create a group conversation between 5 users, including a contact and a non-contact, and a user NOT in a shared course.
    2164          \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
    2165              [$users[1]->id, $users[2]->id, $users[4]->id, $users[7]->id, $users[8]->id], 'Project chat');
    2166  
    2167          // Set as the user performing the search.
    2168          $this->setUser($users[1]);
    2169  
    2170          // Perform a search with $CFG->messagingallusers enabled.
    2171          set_config('messagingallusers', 1);
    2172          $result = core_message_external::message_search_users($users[1]->id, 'search');
    2173          $result = external_api::clean_returnvalue(core_message_external::message_search_users_returns(), $result);
    2174  
    2175          // Confirm that we returns contacts and non-contacts.
    2176          $this->assertArrayHasKey('contacts', $result);
    2177          $this->assertArrayHasKey('noncontacts', $result);
    2178          $contacts = $result['contacts'];
    2179          $noncontacts = $result['noncontacts'];
    2180  
    2181          // Check that we retrieved the correct contacts.
    2182          $this->assertCount(2, $contacts);
    2183          $this->assertEquals($users[2]->id, $contacts[0]['id']);
    2184          $this->assertEquals($users[3]->id, $contacts[1]['id']);
    2185  
    2186          // Verify the correct conversations were returned for the contacts.
    2187          $this->assertCount(2, $contacts[0]['conversations']);
    2188          // We can't rely on the ordering of conversations within the results, so sort by id first.
    2189          usort($contacts[0]['conversations'], function($a, $b) {
    2190              return $b['id'] <=> $a['id'];
    2191          });
    2192          $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $contacts[0]['conversations'][0]['type']);
    2193          $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $contacts[0]['conversations'][1]['type']);
    2194  
    2195          $this->assertCount(0, $contacts[1]['conversations']);
    2196  
    2197          // Check that we retrieved the correct non-contacts.
    2198          // If site wide messaging is enabled, we expect to be able to search for any users whose profiles we can view.
    2199          // In this case, as a student, that's the course contact for course2 and those noncontacts sharing a course with user1.
    2200          $this->assertCount(4, $noncontacts);
    2201          $this->assertEquals($users[1]->id, $noncontacts[0]['id']);
    2202          $this->assertEquals($users[6]->id, $noncontacts[1]['id']);
    2203          $this->assertEquals($users[7]->id, $noncontacts[2]['id']);
    2204          $this->assertEquals($users[9]->id, $noncontacts[3]['id']);
    2205  
    2206          // Verify the correct conversations were returned for the non-contacts.
    2207          $this->assertCount(1, $noncontacts[1]['conversations']);
    2208          $this->assertCount(1, $noncontacts[2]['conversations']);
    2209          $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $noncontacts[1]['conversations'][0]['type']);
    2210          $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $noncontacts[2]['conversations'][0]['type']);
    2211          $this->assertCount(0, $noncontacts[3]['conversations']);
    2212      }
    2213  
    2214      /**
    2215       * Verify searching for users find themselves when they have self-conversations.
    2216       */
    2217      public function test_message_search_users_self_conversations() {
    2218          $this->resetAfterTest();
    2219  
    2220          // Create some users.
    2221          $user1 = new stdClass();
    2222          $user1->firstname = 'User';
    2223          $user1->lastname = 'One';
    2224          $user1 = $this->getDataGenerator()->create_user($user1);
    2225          $user2 = new stdClass();
    2226          $user2->firstname = 'User';
    2227          $user2->lastname = 'Two';
    2228          $user2 = $this->getDataGenerator()->create_user($user2);
    2229  
    2230          // Get self-conversation for user1.
    2231          $sc1 = \core_message\api::get_self_conversation($user1->id);
    2232          testhelper::send_fake_message_to_conversation($user1, $sc1->id, 'Hi myself!');
    2233  
    2234          // Perform a search as user1.
    2235          $this->setUser($user1);
    2236          $result = core_message_external::message_search_users($user1->id, 'One');
    2237          $result = external_api::clean_returnvalue(core_message_external::message_search_users_returns(), $result);
    2238  
    2239          // Check results are empty.
    2240          $this->assertCount(0, $result['contacts']);
    2241          $this->assertCount(1, $result['noncontacts']);
    2242      }
    2243  
    2244      /**
    2245       * Verify searching for users works even if no matching users from either contacts, or non-contacts can be found.
    2246       */
    2247      public function test_message_search_users_with_empty_result() {
    2248          $this->resetAfterTest();
    2249  
    2250          // Create some users, but make sure neither will match the search term.
    2251          $user1 = new stdClass();
    2252          $user1->firstname = 'User';
    2253          $user1->lastname = 'One';
    2254          $user1 = $this->getDataGenerator()->create_user($user1);
    2255          $user2 = new stdClass();
    2256          $user2->firstname = 'User';
    2257          $user2->lastname = 'Two';
    2258          $user2 = $this->getDataGenerator()->create_user($user2);
    2259  
    2260          // Perform a search as user1.
    2261          $this->setUser($user1);
    2262          $result = core_message_external::message_search_users($user1->id, 'search');
    2263          $result = external_api::clean_returnvalue(core_message_external::message_search_users_returns(), $result);
    2264  
    2265          // Check results are empty.
    2266          $this->assertCount(0, $result['contacts']);
    2267          $this->assertCount(0, $result['noncontacts']);
    2268      }
    2269  
    2270      /**
    2271       * Test verifying that limits and offsets work for both the contacts and non-contacts return data.
    2272       */
    2273      public function test_message_search_users_limit_offset() {
    2274          $this->resetAfterTest();
    2275  
    2276          // Create 20 users.
    2277          $users = [];
    2278          foreach (range(1, 20) as $i) {
    2279              $user = new stdClass();
    2280              $user->firstname = "User search";
    2281              $user->lastname = $i;
    2282              $user = $this->getDataGenerator()->create_user($user);
    2283              $users[$i] = $user;
    2284          }
    2285  
    2286          // Enrol the first 8 users in the same course, but leave them as non-contacts.
    2287          $this->setAdminUser();
    2288          $course1 = $this->getDataGenerator()->create_course();
    2289          foreach (range(1, 8) as $i) {
    2290              $this->getDataGenerator()->enrol_user($users[$i]->id, $course1->id);
    2291          }
    2292  
    2293          // Add 5 users, starting at the 11th user, as contacts for user1.
    2294          foreach (range(11, 15) as $i) {
    2295              \core_message\api::add_contact($users[1]->id, $users[$i]->id);
    2296          }
    2297  
    2298          // Set as the user performing the search.
    2299          $this->setUser($users[1]);
    2300  
    2301          // Search using a limit of 3.
    2302          // This tests the case where we have more results than the limit for both contacts and non-contacts.
    2303          $result = core_message_external::message_search_users($users[1]->id, 'search', 0, 3);
    2304          $result = external_api::clean_returnvalue(core_message_external::message_search_users_returns(), $result);
    2305          $contacts = $result['contacts'];
    2306          $noncontacts = $result['noncontacts'];
    2307  
    2308          // Check that we retrieved the correct contacts.
    2309          $this->assertCount(3, $contacts);
    2310          $this->assertEquals($users[11]->id, $contacts[0]['id']);
    2311          $this->assertEquals($users[12]->id, $contacts[1]['id']);
    2312          $this->assertEquals($users[13]->id, $contacts[2]['id']);
    2313  
    2314          // Check that we retrieved the correct non-contacts.
    2315          // Consider first conversation is self-conversation.
    2316          $this->assertCount(3, $noncontacts);
    2317          $this->assertEquals($users[1]->id, $noncontacts[0]['id']);
    2318          $this->assertEquals($users[2]->id, $noncontacts[1]['id']);
    2319          $this->assertEquals($users[3]->id, $noncontacts[2]['id']);
    2320  
    2321          // Now, offset to get the next batch of results.
    2322          // We expect to see 2 contacts, and 3 non-contacts.
    2323          $result = core_message_external::message_search_users($users[1]->id, 'search', 3, 3);
    2324          $result = external_api::clean_returnvalue(core_message_external::message_search_users_returns(), $result);
    2325          $contacts = $result['contacts'];
    2326          $noncontacts = $result['noncontacts'];
    2327          $this->assertCount(2, $contacts);
    2328          $this->assertEquals($users[14]->id, $contacts[0]['id']);
    2329          $this->assertEquals($users[15]->id, $contacts[1]['id']);
    2330  
    2331          $this->assertCount(3, $noncontacts);
    2332          $this->assertEquals($users[4]->id, $noncontacts[0]['id']);
    2333          $this->assertEquals($users[5]->id, $noncontacts[1]['id']);
    2334          $this->assertEquals($users[6]->id, $noncontacts[2]['id']);
    2335  
    2336          // Now, offset to get the next batch of results.
    2337          // We expect to see 0 contacts, and 2 non-contacts.
    2338          $result = core_message_external::message_search_users($users[1]->id, 'search', 6, 3);
    2339          $result = external_api::clean_returnvalue(core_message_external::message_search_users_returns(), $result);
    2340          $contacts = $result['contacts'];
    2341          $noncontacts = $result['noncontacts'];
    2342          $this->assertCount(0, $contacts);
    2343  
    2344          $this->assertCount(2, $noncontacts);
    2345          $this->assertEquals($users[7]->id, $noncontacts[0]['id']);
    2346          $this->assertEquals($users[8]->id, $noncontacts[1]['id']);
    2347      }
    2348  
    2349      /**
    2350       * Tests searching users as another user having the 'moodle/user:viewdetails' capability.
    2351       */
    2352      public function test_message_search_users_with_cap() {
    2353          $this->resetAfterTest();
    2354          global $DB;
    2355  
    2356          // Create some users.
    2357          $users = [];
    2358          foreach (range(1, 8) as $i) {
    2359              $user = new stdClass();
    2360              $user->firstname = ($i == 4) ? 'User' : 'User search'; // Ensure the fourth user won't match the search term.
    2361              $user->lastname = $i;
    2362              $user = $this->getDataGenerator()->create_user($user);
    2363              $users[$i] = $user;
    2364          }
    2365  
    2366          // Enrol a few users in the same course, but leave them as non-contacts.
    2367          $course1 = $this->getDataGenerator()->create_course();
    2368          $this->setAdminUser();
    2369          $this->getDataGenerator()->enrol_user($users[1]->id, $course1->id);
    2370          $this->getDataGenerator()->enrol_user($users[6]->id, $course1->id);
    2371          $this->getDataGenerator()->enrol_user($users[7]->id, $course1->id);
    2372  
    2373          // Add some other users as contacts.
    2374          \core_message\api::add_contact($users[1]->id, $users[2]->id);
    2375          \core_message\api::add_contact($users[3]->id, $users[1]->id);
    2376          \core_message\api::add_contact($users[1]->id, $users[4]->id);
    2377  
    2378          // Set as the user performing the search.
    2379          $this->setUser($users[1]);
    2380  
    2381          // Grant the authenticated user role the capability 'user:viewdetails' at site context.
    2382          $authenticatedrole = $DB->get_record('role', ['shortname' => 'user'], '*', MUST_EXIST);
    2383          assign_capability('moodle/user:viewdetails', CAP_ALLOW, $authenticatedrole->id, context_system::instance());
    2384  
    2385          // Perform a search with $CFG->messagingallusers disabled.
    2386          set_config('messagingallusers', 0);
    2387          $result = core_message_external::message_search_users($users[1]->id, 'search');
    2388          $result = external_api::clean_returnvalue(core_message_external::message_search_users_returns(), $result);
    2389          $contacts = $result['contacts'];
    2390          $noncontacts = $result['noncontacts'];
    2391  
    2392          // Check that we retrieved the correct contacts.
    2393          $this->assertCount(2, $contacts);
    2394          $this->assertEquals($users[2]->id, $contacts[0]['id']);
    2395          $this->assertEquals($users[3]->id, $contacts[1]['id']);
    2396  
    2397          // Check that we retrieved the correct non-contacts.
    2398          // Site-wide messaging is disabled, so we expect to be able to search for any users whose profile we can view.
    2399          // Consider first conversations is self-conversation.
    2400          $this->assertCount(3, $noncontacts);
    2401          $this->assertEquals($users[1]->id, $noncontacts[0]['id']);
    2402          $this->assertEquals($users[6]->id, $noncontacts[1]['id']);
    2403          $this->assertEquals($users[7]->id, $noncontacts[2]['id']);
    2404      }
    2405  
    2406      /**
    2407       * Tests searching users as another user without the 'moodle/user:viewdetails' capability.
    2408       */
    2409      public function test_message_search_users_without_cap() {
    2410          $this->resetAfterTest();
    2411  
    2412          // Create some users.
    2413          $user1 = $this->getDataGenerator()->create_user();
    2414          $user2 = $this->getDataGenerator()->create_user();
    2415  
    2416          // The person doing the search for another user.
    2417          $this->setUser($user1);
    2418  
    2419          // Ensure an exception is thrown.
    2420          $this->expectException('moodle_exception');
    2421          core_message_external::message_search_users($user2->id, 'User');
    2422          $this->assertDebuggingCalled();
    2423      }
    2424  
    2425      /**
    2426       * Tests searching users with messaging disabled.
    2427       */
    2428      public function test_message_search_users_messaging_disabled() {
    2429          $this->resetAfterTest();
    2430  
    2431          // Create some skeleton data just so we can call the WS.
    2432          $user = $this->getDataGenerator()->create_user();
    2433  
    2434          // The person doing the search.
    2435          $this->setUser($user);
    2436  
    2437          // Disable messaging.
    2438          set_config('messaging', 0);
    2439  
    2440          // Ensure an exception is thrown.
    2441          $this->expectException('moodle_exception');
    2442          core_message_external::message_search_users($user->id, 'User');
    2443      }
    2444  
    2445      /**
    2446       * Tests searching messages.
    2447       */
    2448      public function test_messagearea_search_messages() {
    2449          $this->resetAfterTest(true);
    2450  
    2451          // Create some users.
    2452          $user1 = self::getDataGenerator()->create_user();
    2453          $user2 = self::getDataGenerator()->create_user();
    2454  
    2455          // The person doing the search.
    2456          $this->setUser($user1);
    2457  
    2458          // Send some messages back and forth.
    2459          $time = time();
    2460          $this->send_message($user1, $user2, 'Yo!', 0, $time);
    2461          $this->send_message($user2, $user1, 'Sup mang?', 0, $time + 1);
    2462          $this->send_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 2);
    2463          $this->send_message($user2, $user1, 'Word.', 0, $time + 3);
    2464          $convid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
    2465  
    2466          // Perform a search.
    2467          $result = core_message_external::data_for_messagearea_search_messages($user1->id, 'o');
    2468  
    2469          // We need to execute the return values cleaning process to simulate the web service server.
    2470          $result = external_api::clean_returnvalue(core_message_external::data_for_messagearea_search_messages_returns(), $result);
    2471  
    2472          // Confirm the data is correct.
    2473          $messages = $result['contacts'];
    2474          $this->assertCount(2, $messages);
    2475  
    2476          $message1 = $messages[0];
    2477          $message2 = $messages[1];
    2478  
    2479          $this->assertEquals($user2->id, $message1['userid']);
    2480          $this->assertEquals(fullname($user2), $message1['fullname']);
    2481          $this->assertTrue($message1['ismessaging']);
    2482          $this->assertFalse($message1['sentfromcurrentuser']);
    2483          $this->assertEquals('Word.', $message1['lastmessage']);
    2484          $this->assertNotEmpty($message1['messageid']);
    2485          $this->assertNull($message1['isonline']);
    2486          $this->assertFalse($message1['isread']);
    2487          $this->assertFalse($message1['isblocked']);
    2488          $this->assertNull($message1['unreadcount']);
    2489          $this->assertEquals($convid, $message1['conversationid']);
    2490  
    2491          $this->assertEquals($user2->id, $message2['userid']);
    2492          $this->assertEquals(fullname($user2), $message2['fullname']);
    2493          $this->assertTrue($message2['ismessaging']);
    2494          $this->assertTrue($message2['sentfromcurrentuser']);
    2495          $this->assertEquals('Yo!', $message2['lastmessage']);
    2496          $this->assertNotEmpty($message2['messageid']);
    2497          $this->assertNull($message2['isonline']);
    2498          $this->assertTrue($message2['isread']);
    2499          $this->assertFalse($message2['isblocked']);
    2500          $this->assertNull($message2['unreadcount']);
    2501          $this->assertEquals($convid, $message2['conversationid']);
    2502      }
    2503  
    2504      /**
    2505       * Tests searching messages as another user.
    2506       */
    2507      public function test_messagearea_search_messages_as_other_user() {
    2508          $this->resetAfterTest(true);
    2509  
    2510          // The person doing the search.
    2511          $this->setAdminUser();
    2512  
    2513          // Create some users.
    2514          $user1 = self::getDataGenerator()->create_user();
    2515          $user2 = self::getDataGenerator()->create_user();
    2516  
    2517          // Send some messages back and forth.
    2518          $time = time();
    2519          $this->send_message($user1, $user2, 'Yo!', 0, $time);
    2520          $this->send_message($user2, $user1, 'Sup mang?', 0, $time + 1);
    2521          $this->send_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 2);
    2522          $this->send_message($user2, $user1, 'Word.', 0, $time + 3);
    2523  
    2524          // Perform a search.
    2525          $result = core_message_external::data_for_messagearea_search_messages($user1->id, 'o');
    2526  
    2527          // We need to execute the return values cleaning process to simulate the web service server.
    2528          $result = external_api::clean_returnvalue(core_message_external::data_for_messagearea_search_messages_returns(),
    2529              $result);
    2530  
    2531          // Confirm the data is correct.
    2532          $messages = $result['contacts'];
    2533          $this->assertCount(2, $messages);
    2534  
    2535          $message1 = $messages[0];
    2536          $message2 = $messages[1];
    2537  
    2538          $this->assertEquals($user2->id, $message1['userid']);
    2539          $this->assertEquals(fullname($user2), $message1['fullname']);
    2540          $this->assertTrue($message1['ismessaging']);
    2541          $this->assertFalse($message1['sentfromcurrentuser']);
    2542          $this->assertEquals('Word.', $message1['lastmessage']);
    2543          $this->assertNotEmpty($message1['messageid']);
    2544          $this->assertFalse($message1['isonline']);
    2545          $this->assertFalse($message1['isread']);
    2546          $this->assertFalse($message1['isblocked']);
    2547          $this->assertNull($message1['unreadcount']);
    2548  
    2549          $this->assertEquals($user2->id, $message2['userid']);
    2550          $this->assertEquals(fullname($user2), $message2['fullname']);
    2551          $this->assertTrue($message2['ismessaging']);
    2552          $this->assertTrue($message2['sentfromcurrentuser']);
    2553          $this->assertEquals('Yo!', $message2['lastmessage']);
    2554          $this->assertNotEmpty($message2['messageid']);
    2555          $this->assertFalse($message2['isonline']);
    2556          $this->assertTrue($message2['isread']);
    2557          $this->assertFalse($message2['isblocked']);
    2558          $this->assertNull($message2['unreadcount']);
    2559      }
    2560  
    2561      /**
    2562       * Tests searching messages as another user without the proper capabilities.
    2563       */
    2564      public function test_messagearea_search_messages_as_other_user_without_cap() {
    2565          $this->resetAfterTest(true);
    2566  
    2567          // Create some users.
    2568          $user1 = self::getDataGenerator()->create_user();
    2569          $user2 = self::getDataGenerator()->create_user();
    2570  
    2571          // The person doing the search for another user.
    2572          $this->setUser($user1);
    2573  
    2574          // Ensure an exception is thrown.
    2575          $this->expectException('moodle_exception');
    2576          core_message_external::data_for_messagearea_search_messages($user2->id, 'Search');
    2577      }
    2578  
    2579      /**
    2580       * Tests searching messages with messaging disabled
    2581       */
    2582      public function test_messagearea_search_messages_messaging_disabled() {
    2583          global $CFG;
    2584  
    2585          $this->resetAfterTest(true);
    2586  
    2587          // Create some skeleton data just so we can call the WS.
    2588          $user = self::getDataGenerator()->create_user();
    2589  
    2590          // The person doing the search .
    2591          $this->setUser($user);
    2592  
    2593          // Disable messaging.
    2594          $CFG->messaging = 0;
    2595  
    2596          // Ensure an exception is thrown.
    2597          $this->expectException('moodle_exception');
    2598          core_message_external::data_for_messagearea_search_messages($user->id, 'Search');
    2599      }
    2600  
    2601      /**
    2602       * Tests retrieving contacts.
    2603       */
    2604      public function test_get_user_contacts() {
    2605          $this->resetAfterTest(true);
    2606  
    2607          // Create some users.
    2608          $user1 = self::getDataGenerator()->create_user();
    2609  
    2610          // Set as the user.
    2611          $this->setUser($user1);
    2612  
    2613          $user2 = new stdClass();
    2614          $user2->firstname = 'User';
    2615          $user2->lastname = 'A';
    2616          $user2 = self::getDataGenerator()->create_user($user2);
    2617  
    2618          $user3 = new stdClass();
    2619          $user3->firstname = 'User';
    2620          $user3->lastname = 'B';
    2621          $user3 = self::getDataGenerator()->create_user($user3);
    2622  
    2623          $user4 = new stdClass();
    2624          $user4->firstname = 'User';
    2625          $user4->lastname = 'C';
    2626          $user4 = self::getDataGenerator()->create_user($user4);
    2627  
    2628          $user5 = new stdClass();
    2629          $user5->firstname = 'User';
    2630          $user5->lastname = 'D';
    2631          $user5 = self::getDataGenerator()->create_user($user5);
    2632  
    2633          // Add some users as contacts.
    2634          \core_message\api::add_contact($user1->id, $user2->id);
    2635          \core_message\api::add_contact($user1->id, $user3->id);
    2636          \core_message\api::add_contact($user1->id, $user4->id);
    2637  
    2638          // Retrieve the contacts.
    2639          $result = core_message_external::get_user_contacts($user1->id);
    2640  
    2641          // We need to execute the return values cleaning process to simulate the web service server.
    2642          $result = external_api::clean_returnvalue(core_message_external::get_user_contacts_returns(),
    2643              $result);
    2644  
    2645          // Confirm the data is correct.
    2646          $contacts = $result;
    2647          usort($contacts, ['static', 'sort_contacts_id']);
    2648          $this->assertCount(3, $contacts);
    2649  
    2650          $contact1 = array_shift($contacts);
    2651          $contact2 = array_shift($contacts);
    2652          $contact3 = array_shift($contacts);
    2653  
    2654          $this->assertEquals($user2->id, $contact1['id']);
    2655          $this->assertEquals(fullname($user2), $contact1['fullname']);
    2656          $this->assertTrue($contact1['iscontact']);
    2657  
    2658          $this->assertEquals($user3->id, $contact2['id']);
    2659          $this->assertEquals(fullname($user3), $contact2['fullname']);
    2660          $this->assertTrue($contact2['iscontact']);
    2661  
    2662          $this->assertEquals($user4->id, $contact3['id']);
    2663          $this->assertEquals(fullname($user4), $contact3['fullname']);
    2664          $this->assertTrue($contact3['iscontact']);
    2665      }
    2666  
    2667      /**
    2668       * Tests retrieving contacts as another user.
    2669       */
    2670      public function test_get_user_contacts_as_other_user() {
    2671          $this->resetAfterTest(true);
    2672  
    2673          $this->setAdminUser();
    2674  
    2675          // Create some users.
    2676          $user1 = self::getDataGenerator()->create_user();
    2677  
    2678          $user2 = new stdClass();
    2679          $user2->firstname = 'User';
    2680          $user2->lastname = 'A';
    2681          $user2 = self::getDataGenerator()->create_user($user2);
    2682  
    2683          $user3 = new stdClass();
    2684          $user3->firstname = 'User';
    2685          $user3->lastname = 'B';
    2686          $user3 = self::getDataGenerator()->create_user($user3);
    2687  
    2688          $user4 = new stdClass();
    2689          $user4->firstname = 'User';
    2690          $user4->lastname = 'C';
    2691          $user4 = self::getDataGenerator()->create_user($user4);
    2692  
    2693          $user5 = new stdClass();
    2694          $user5->firstname = 'User';
    2695          $user5->lastname = 'D';
    2696          $user5 = self::getDataGenerator()->create_user($user5);
    2697  
    2698          // Add some users as contacts.
    2699          \core_message\api::add_contact($user1->id, $user2->id);
    2700          \core_message\api::add_contact($user1->id, $user3->id);
    2701          \core_message\api::add_contact($user1->id, $user4->id);
    2702  
    2703          // Retrieve the contacts.
    2704          $result = core_message_external::get_user_contacts($user1->id);
    2705  
    2706          // We need to execute the return values cleaning process to simulate the web service server.
    2707          $result = external_api::clean_returnvalue(core_message_external::get_user_contacts_returns(),
    2708              $result);
    2709  
    2710          // Confirm the data is correct.
    2711          $contacts = $result;
    2712          usort($contacts, ['static', 'sort_contacts_id']);
    2713          $this->assertCount(3, $contacts);
    2714  
    2715          $contact1 = array_shift($contacts);
    2716          $contact2 = array_shift($contacts);
    2717          $contact3 = array_shift($contacts);
    2718  
    2719          $this->assertEquals($user2->id, $contact1['id']);
    2720          $this->assertEquals(fullname($user2), $contact1['fullname']);
    2721          $this->assertTrue($contact1['iscontact']);
    2722  
    2723          $this->assertEquals($user3->id, $contact2['id']);
    2724          $this->assertEquals(fullname($user3), $contact2['fullname']);
    2725          $this->assertTrue($contact2['iscontact']);
    2726  
    2727          $this->assertEquals($user4->id, $contact3['id']);
    2728          $this->assertEquals(fullname($user4), $contact3['fullname']);
    2729          $this->assertTrue($contact3['iscontact']);
    2730      }
    2731  
    2732      /**
    2733       * Tests retrieving contacts as another user without the proper capabilities.
    2734       */
    2735      public function test_get_user_contacts_as_other_user_without_cap() {
    2736          $this->resetAfterTest(true);
    2737  
    2738          // Create some users.
    2739          $user1 = self::getDataGenerator()->create_user();
    2740          $user2 = self::getDataGenerator()->create_user();
    2741  
    2742          // The person retrieving the contacts for another user.
    2743          $this->setUser($user1);
    2744  
    2745          // Perform the WS call and ensure an exception is thrown.
    2746          $this->expectException('moodle_exception');
    2747          core_message_external::get_user_contacts($user2->id);
    2748      }
    2749  
    2750      /**
    2751       * Tests retrieving contacts with messaging disabled.
    2752       */
    2753      public function test_get_user_contacts_messaging_disabled() {
    2754          global $CFG;
    2755  
    2756          $this->resetAfterTest(true);
    2757  
    2758          // Create some skeleton data just so we can call the WS.
    2759          $user = self::getDataGenerator()->create_user();
    2760  
    2761          // The person retrieving the contacts.
    2762          $this->setUser($user);
    2763  
    2764          // Disable messaging.
    2765          $CFG->messaging = 0;
    2766  
    2767          // Perform the WS call and ensure we are shown that it is disabled.
    2768          $this->expectException('moodle_exception');
    2769          core_message_external::get_user_contacts($user->id);
    2770      }
    2771  
    2772      /**
    2773       * Test getting contacts when there are no results.
    2774       */
    2775      public function test_get_user_contacts_no_results() {
    2776          $this->resetAfterTest();
    2777  
    2778          $user1 = self::getDataGenerator()->create_user();
    2779  
    2780          $this->setUser($user1);
    2781  
    2782          $requests = core_message_external::get_user_contacts($user1->id);
    2783          $requests = external_api::clean_returnvalue(core_message_external::get_user_contacts_returns(), $requests);
    2784  
    2785          $this->assertEmpty($requests);
    2786      }
    2787  
    2788      /**
    2789       * Tests get_conversation_messages for retrieving messages.
    2790       */
    2791      public function test_get_conversation_messages() {
    2792          $this->resetAfterTest(true);
    2793  
    2794          // Create some users.
    2795          $user1 = self::getDataGenerator()->create_user();
    2796          $user2 = self::getDataGenerator()->create_user();
    2797          $user3 = self::getDataGenerator()->create_user();
    2798          $user4 = self::getDataGenerator()->create_user();
    2799          $user5 = self::getDataGenerator()->create_user();
    2800  
    2801          // Create group conversation.
    2802          $conversation = \core_message\api::create_conversation(
    2803              \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
    2804              [$user1->id, $user2->id, $user3->id, $user4->id]
    2805          );
    2806  
    2807          // The person asking for the messages.
    2808          $this->setUser($user1);
    2809  
    2810          // Send some messages back and forth.
    2811          $time = time();
    2812          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time);
    2813          testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Sup mang?', $time + 1);
    2814          testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Writing PHPUnit tests!', $time + 2);
    2815          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Word.', $time + 3);
    2816  
    2817          // Retrieve the messages.
    2818          $result = core_message_external::get_conversation_messages($user1->id, $conversation->id);
    2819  
    2820          // We need to execute the return values cleaning process to simulate the web service server.
    2821          $result = external_api::clean_returnvalue(core_message_external::get_conversation_messages_returns(),
    2822              $result);
    2823  
    2824          // Check the results are correct.
    2825          $this->assertEquals($conversation->id, $result['id']);
    2826  
    2827          // Confirm the members data is correct.
    2828          $members = $result['members'];
    2829          $this->assertCount(3, $members);
    2830          $membersid = [$members[0]['id'], $members[1]['id'], $members[2]['id']];
    2831          $this->assertContainsEquals($user1->id, $membersid);
    2832          $this->assertContainsEquals($user2->id, $membersid);
    2833          $this->assertContainsEquals($user3->id, $membersid);
    2834  
    2835          $membersfullnames = [$members[0]['fullname'], $members[1]['fullname'], $members[2]['fullname']];
    2836          $this->assertContainsEquals(fullname($user1), $membersfullnames);
    2837          $this->assertContainsEquals(fullname($user2), $membersfullnames);
    2838          $this->assertContainsEquals(fullname($user3), $membersfullnames);
    2839  
    2840          // Confirm the messages data is correct.
    2841          $messages = $result['messages'];
    2842          $this->assertCount(4, $messages);
    2843  
    2844          $message1 = $messages[0];
    2845          $message2 = $messages[1];
    2846          $message3 = $messages[2];
    2847          $message4 = $messages[3];
    2848  
    2849          $this->assertEquals($user1->id, $message1['useridfrom']);
    2850          $this->assertStringContainsString('Yo!', $message1['text']);
    2851  
    2852          $this->assertEquals($user3->id, $message2['useridfrom']);
    2853          $this->assertStringContainsString('Sup mang?', $message2['text']);
    2854  
    2855          $this->assertEquals($user2->id, $message3['useridfrom']);
    2856          $this->assertStringContainsString('Writing PHPUnit tests!', $message3['text']);
    2857  
    2858          $this->assertEquals($user1->id, $message4['useridfrom']);
    2859          $this->assertStringContainsString('Word.', $message4['text']);
    2860      }
    2861  
    2862      /**
    2863       * Tests get_conversation_messages for retrieving messages using timefrom parameter.
    2864       */
    2865      public function test_get_conversation_messages_timefrom() {
    2866          $this->resetAfterTest(true);
    2867  
    2868          // Create some users.
    2869          $user1 = self::getDataGenerator()->create_user();
    2870          $user2 = self::getDataGenerator()->create_user();
    2871          $user3 = self::getDataGenerator()->create_user();
    2872          $user4 = self::getDataGenerator()->create_user();
    2873  
    2874          // Create group conversation.
    2875          $conversation = \core_message\api::create_conversation(
    2876              \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
    2877              [$user1->id, $user2->id, $user3->id]
    2878          );
    2879  
    2880          // The person asking for the messages.
    2881          $this->setUser($user1);
    2882  
    2883          // Send some messages back and forth.
    2884          $time = time();
    2885          testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time - 4);
    2886          testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time - 3);
    2887          testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 3', $time - 2);
    2888          testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 4', $time - 1);
    2889  
    2890          // Retrieve the messages from $time - 3, which should be the 3 most recent messages.
    2891          $result = core_message_external::get_conversation_messages($user1->id, $conversation->id, 0, 0, false, $time - 3);
    2892  
    2893          // We need to execute the return values cleaning process to simulate the web service server.
    2894          $result = external_api::clean_returnvalue(core_message_external::get_conversation_messages_returns(),
    2895              $result);
    2896  
    2897          // Check the results are correct.
    2898          $this->assertEquals($conversation->id, $result['id']);
    2899  
    2900          // Confirm the messages data is correct.
    2901          $messages = $result['messages'];
    2902          $this->assertCount(3, $messages);
    2903  
    2904          $message1 = $messages[0];
    2905          $message2 = $messages[1];
    2906          $message3 = $messages[2];
    2907  
    2908          $this->assertStringContainsString('Message 2', $message1['text']);
    2909          $this->assertStringContainsString('Message 3', $message2['text']);
    2910          $this->assertStringContainsString('Message 4', $message3['text']);
    2911  
    2912          // Confirm the members data is correct.
    2913