Search moodle.org's
Developer Documentation

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