MDL-70897 various: uasort callback can not return bool
[moodle.git] / message / tests / externallib_test.php
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/>.
17 /**
18  * External message functions unit tests
19  *
20  * @package    core_message
21  * @category   external
22  * @copyright  2012 Jerome Mouneyrac
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
30 require_once($CFG->dirroot . '/webservice/tests/helpers.php');
31 require_once($CFG->dirroot . '/message/externallib.php');
33 use \core_message\tests\helper as testhelper;
35 class core_message_externallib_testcase extends externallib_advanced_testcase {
37     /**
38      * Tests set up
39      */
40     protected function setUp(): void {
41         global $CFG;
43         require_once($CFG->dirroot . '/message/lib.php');
44     }
46     /**
47      * Send a fake message.
48      *
49      * {@link message_send()} does not support transaction, this function will simulate a message
50      * sent from a user to another. We should stop using it once {@link message_send()} will support
51      * transactions. This is not clean at all, this is just used to add rows to the table.
52      *
53      * @param stdClass $userfrom user object of the one sending the message.
54      * @param stdClass $userto user object of the one receiving the message.
55      * @param string $message message to send.
56      * @param int $notification is the message a notification.
57      * @param int $time the time the message was sent
58      */
59     protected function send_message($userfrom, $userto, $message = 'Hello world!', $notification = 0, $time = 0) {
60         global $DB;
62         if (empty($time)) {
63             $time = time();
64         }
66         if ($notification) {
67             $record = new stdClass();
68             $record->useridfrom = $userfrom->id;
69             $record->useridto = $userto->id;
70             $record->subject = 'No subject';
71             $record->fullmessage = $message;
72             $record->smallmessage = $message;
73             $record->timecreated = $time;
75             return $DB->insert_record('notifications', $record);
76         }
78         if (!$conversationid = \core_message\api::get_conversation_between_users([$userfrom->id, $userto->id])) {
79             $conversation = \core_message\api::create_conversation(
80                 \core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
81                 [
82                     $userfrom->id,
83                     $userto->id
84                 ]
85             );
86             $conversationid = $conversation->id;
87         }
89         // Ok, send the message.
90         $record = new stdClass();
91         $record->useridfrom = $userfrom->id;
92         $record->conversationid = $conversationid;
93         $record->subject = 'No subject';
94         $record->fullmessage = $message;
95         $record->smallmessage = $message;
96         $record->timecreated = $time;
98         return $DB->insert_record('messages', $record);
99     }
101     /**
102      * Test send_instant_messages.
103      */
104     public function test_send_instant_messages() {
105         global $DB, $USER;
107         $this->resetAfterTest();
109         // Transactions used in tests, tell phpunit use alternative reset method.
110         $this->preventResetByRollback();
112         $user1 = self::getDataGenerator()->create_user();
113         $user2 = self::getDataGenerator()->create_user();
115         $this->setUser($user1);
117         // Create test message data.
118         $message1 = array();
119         $message1['touserid'] = $user2->id;
120         $message1['text'] = 'the message.';
121         $message1['clientmsgid'] = 4;
122         $messages = array($message1);
124         $sentmessages = core_message_external::send_instant_messages($messages);
125         $sentmessages = external_api::clean_returnvalue(core_message_external::send_instant_messages_returns(), $sentmessages);
126         $this->assertEquals(
127             get_string('usercantbemessaged', 'message', fullname(\core_user::get_user($message1['touserid']))),
128             array_pop($sentmessages)['errormessage']
129         );
131         // Add the user1 as a contact.
132         \core_message\api::add_contact($user1->id, $user2->id);
134         // Send message again. Now it should work properly.
135         $sentmessages = core_message_external::send_instant_messages($messages);
136         // We need to execute the return values cleaning process to simulate the web service server.
137         $sentmessages = external_api::clean_returnvalue(core_message_external::send_instant_messages_returns(), $sentmessages);
139         $sentmessage = reset($sentmessages);
141         $sql = "SELECT m.*, mcm.userid as useridto
142                  FROM {messages} m
143            INNER JOIN {message_conversations} mc
144                    ON m.conversationid = mc.id
145            INNER JOIN {message_conversation_members} mcm
146                    ON mcm.conversationid = mc.id
147                 WHERE mcm.userid != ?
148                   AND m.id = ?";
149         $themessage = $DB->get_record_sql($sql, [$USER->id, $sentmessage['msgid']]);
151         // Confirm that the message was inserted correctly.
152         $this->assertEquals($themessage->useridfrom, $user1->id);
153         $this->assertEquals($themessage->useridto, $message1['touserid']);
154         $this->assertEquals($themessage->smallmessage, $message1['text']);
155         $this->assertEquals($sentmessage['clientmsgid'], $message1['clientmsgid']);
156     }
158     /**
159      * Test send_instant_messages with a message text longer than permitted.
160      */
161     public function test_send_instant_messages_long_text() {
162         global $CFG;
164         $this->resetAfterTest(true);
166         // Transactions used in tests, tell phpunit use alternative reset method.
167         $this->preventResetByRollback();
169         $user1 = self::getDataGenerator()->create_user();
170         $user2 = self::getDataGenerator()->create_user();
172         $this->setUser($user1);
174         // Create test message data.
175         $message1 = [
176             'touserid' => $user2->id,
177             'text' => str_repeat("M", \core_message\api::MESSAGE_MAX_LENGTH + 100),
178             'clientmsgid' => 4,
179         ];
180         $messages = [$message1];
182         // Add the user1 as a contact.
183         \core_message\api::add_contact($user1->id, $user2->id);
185         $sentmessages = core_message_external::send_instant_messages($messages);
186         $sentmessages = external_api::clean_returnvalue(core_message_external::send_instant_messages_returns(), $sentmessages);
187         $this->assertEquals(
188             get_string('errormessagetoolong', 'message'),
189             array_pop($sentmessages)['errormessage']
190         );
191     }
193     /**
194      * Test send_instant_messages to a user who has blocked you.
195      */
196     public function test_send_instant_messages_blocked_user() {
197         global $DB;
199         $this->resetAfterTest();
201         // Transactions used in tests, tell phpunit use alternative reset method.
202         $this->preventResetByRollback();
204         $user1 = self::getDataGenerator()->create_user();
205         $user2 = self::getDataGenerator()->create_user();
207         $this->setUser($user1);
209         \core_message\api::block_user($user2->id, $user1->id);
211         // Create test message data.
212         $message1 = array();
213         $message1['touserid'] = $user2->id;
214         $message1['text'] = 'the message.';
215         $message1['clientmsgid'] = 4;
216         $messages = array($message1);
218         $sentmessages = core_message_external::send_instant_messages($messages);
219         $sentmessages = external_api::clean_returnvalue(core_message_external::send_instant_messages_returns(), $sentmessages);
221         $sentmessage = reset($sentmessages);
223         $this->assertEquals(get_string('usercantbemessaged', 'message', fullname($user2)), $sentmessage['errormessage']);
225         $this->assertEquals(0, $DB->count_records('messages'));
226     }
228     /**
229      * Test send_instant_messages when sending a message to a non-contact who has blocked non-contacts.
230      */
231     public function test_send_instant_messages_block_non_contacts() {
232         global $DB;
234         $this->resetAfterTest(true);
236         // Transactions used in tests, tell phpunit use alternative reset method.
237         $this->preventResetByRollback();
239         $user1 = self::getDataGenerator()->create_user();
240         $user2 = self::getDataGenerator()->create_user();
242         $this->setUser($user1);
244         // Set the user preference so user 2 does not accept messages from non-contacts.
245         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2);
247         // Create test message data.
248         $message1 = array();
249         $message1['touserid'] = $user2->id;
250         $message1['text'] = 'the message.';
251         $message1['clientmsgid'] = 4;
252         $messages = array($message1);
254         $sentmessages = core_message_external::send_instant_messages($messages);
255         $sentmessages = external_api::clean_returnvalue(core_message_external::send_instant_messages_returns(), $sentmessages);
257         $sentmessage = reset($sentmessages);
259         $this->assertEquals(get_string('usercantbemessaged', 'message', fullname($user2)), $sentmessage['errormessage']);
261         $this->assertEquals(0, $DB->count_records('messages'));
262     }
264     /**
265      * Test send_instant_messages when sending a message to a contact who has blocked non-contacts.
266      */
267     public function test_send_instant_messages_block_non_contacts_but_am_contact() {
268         global $DB, $USER;
270         $this->resetAfterTest(true);
272         // Transactions used in tests, tell phpunit use alternative reset method.
273         $this->preventResetByRollback();
275         $user1 = self::getDataGenerator()->create_user();
276         $user2 = self::getDataGenerator()->create_user();
278         $this->setUser($user1);
280         // Set the user preference so user 2 does not accept messages from non-contacts.
281         set_user_preference('message_blocknoncontacts', \core_message\api::MESSAGE_PRIVACY_ONLYCONTACTS, $user2);
283         \core_message\api::add_contact($user1->id, $user2->id);
285         // Create test message data.
286         $message1 = array();
287         $message1['touserid'] = $user2->id;
288         $message1['text'] = 'the message.';
289         $message1['clientmsgid'] = 4;
290         $messages = array($message1);
292         $sentmessages = core_message_external::send_instant_messages($messages);
293         $sentmessages = external_api::clean_returnvalue(core_message_external::send_instant_messages_returns(), $sentmessages);
295         $sentmessage = reset($sentmessages);
297         $sql = "SELECT m.*, mcm.userid as useridto
298                  FROM {messages} m
299            INNER JOIN {message_conversations} mc
300                    ON m.conversationid = mc.id
301            INNER JOIN {message_conversation_members} mcm
302                    ON mcm.conversationid = mc.id
303                 WHERE mcm.userid != ?
304                   AND m.id = ?";
305         $themessage = $DB->get_record_sql($sql, [$USER->id, $sentmessage['msgid']]);
307         // Confirm that the message was inserted correctly.
308         $this->assertEquals($themessage->useridfrom, $user1->id);
309         $this->assertEquals($themessage->useridto, $message1['touserid']);
310         $this->assertEquals($themessage->smallmessage, $message1['text']);
311         $this->assertEquals($sentmessage['clientmsgid'], $message1['clientmsgid']);
312     }
314     /**
315      * Test send_instant_messages with no capabilities
316      */
317     public function test_send_instant_messages_no_capability() {
318         global $DB;
320         $this->resetAfterTest(true);
322         // Transactions used in tests, tell phpunit use alternative reset method.
323         $this->preventResetByRollback();
325         $user1 = self::getDataGenerator()->create_user();
326         $user2 = self::getDataGenerator()->create_user();
328         $this->setUser($user1);
330         // Unset the required capabilities by the external function.
331         $contextid = context_system::instance()->id;
332         $userrole = $DB->get_record('role', array('shortname' => 'user'));
333         $this->unassignUserCapability('moodle/site:sendmessage', $contextid, $userrole->id);
335         // Create test message data.
336         $message1 = array();
337         $message1['touserid'] = $user2->id;
338         $message1['text'] = 'the message.';
339         $message1['clientmsgid'] = 4;
340         $messages = array($message1);
342         $this->expectException('required_capability_exception');
343         core_message_external::send_instant_messages($messages);
344     }
346     /**
347      * Test send_instant_messages when messaging is disabled.
348      */
349     public function test_send_instant_messages_messaging_disabled() {
350         global $CFG;
352         $this->resetAfterTest(true);
354         // Transactions used in tests, tell phpunit use alternative reset method.
355         $this->preventResetByRollback();
357         $user1 = self::getDataGenerator()->create_user();
358         $user2 = self::getDataGenerator()->create_user();
360         $this->setUser($user1);
362         // Disable messaging.
363         $CFG->messaging = 0;
365         // Create test message data.
366         $message1 = array();
367         $message1['touserid'] = $user2->id;
368         $message1['text'] = 'the message.';
369         $message1['clientmsgid'] = 4;
370         $messages = array($message1);
372         $this->expectException('moodle_exception');
373         core_message_external::send_instant_messages($messages);
374     }
376     /**
377      * Test delete_contacts.
378      */
379     public function test_delete_contacts() {
380         $this->resetAfterTest(true);
382         $user1 = self::getDataGenerator()->create_user();
383         $user2 = self::getDataGenerator()->create_user();
384         $user3 = self::getDataGenerator()->create_user();
385         $user4 = self::getDataGenerator()->create_user();
386         $user5 = self::getDataGenerator()->create_user();
387         $user6 = self::getDataGenerator()->create_user();
388         $this->setUser($user1);
390         \core_message\api::add_contact($user1->id, $user3->id);
391         \core_message\api::add_contact($user1->id, $user4->id);
392         \core_message\api::add_contact($user1->id, $user5->id);
393         \core_message\api::add_contact($user1->id, $user6->id);
395         // Removing a non-contact.
396         $return = core_message_external::delete_contacts(array($user2->id));
397         $this->assertNull($return);
399         // Removing one contact.
400         $return = core_message_external::delete_contacts(array($user3->id));
401         $this->assertNull($return);
403         // Removing multiple contacts.
404         $return = core_message_external::delete_contacts(array($user4->id, $user5->id));
405         $this->assertNull($return);
407         // Removing contact from unexisting user.
408         $return = core_message_external::delete_contacts(array(99999));
409         $this->assertNull($return);
411         // Removing mixed valid and invalid data.
412         $return = core_message_external::delete_contacts(array($user6->id, 99999));
413         $this->assertNull($return);
415         // Try to delete a contact of another user contact list, should throw an exception.
416         // All assertions must be added before this point.
417         $this->expectException('required_capability_exception');
418         core_message_external::delete_contacts(array($user2->id), $user3->id);
419     }
421     /**
422      * Test getting contact requests.
423      */
424     public function test_get_contact_requests() {
425         global $PAGE;
427         $this->resetAfterTest();
429         $user1 = self::getDataGenerator()->create_user();
430         $user2 = self::getDataGenerator()->create_user();
431         $user3 = self::getDataGenerator()->create_user();
433         $this->setUser($user1);
435         // Block one user, their request should not show up.
436         \core_message\api::block_user($user1->id, $user3->id);
438         \core_message\api::create_contact_request($user2->id, $user1->id);
439         \core_message\api::create_contact_request($user3->id, $user1->id);
441         $requests = core_message_external::get_contact_requests($user1->id);
442         $requests = external_api::clean_returnvalue(core_message_external::get_contact_requests_returns(), $requests);
444         $this->assertCount(1, $requests);
446         $request = reset($requests);
447         $userpicture = new \user_picture($user2);
448         $profileimageurl = $userpicture->get_url($PAGE)->out(false);
450         $this->assertEquals($user2->id, $request['id']);
451         $this->assertEquals(fullname($user2), $request['fullname']);
452         $this->assertArrayHasKey('profileimageurl', $request);
453         $this->assertArrayHasKey('profileimageurlsmall', $request);
454         $this->assertArrayHasKey('isonline', $request);
455         $this->assertArrayHasKey('showonlinestatus', $request);
456         $this->assertArrayHasKey('isblocked', $request);
457         $this->assertArrayHasKey('iscontact', $request);
458     }
460     /**
461      * Test the get_contact_requests() function when the user has blocked the sender of the request.
462      */
463     public function test_get_contact_requests_blocked_sender() {
464         $this->resetAfterTest();
465         $user1 = self::getDataGenerator()->create_user();
466         $user2 = self::getDataGenerator()->create_user();
468         // User1 blocks User2.
469         \core_message\api::block_user($user1->id, $user2->id);
471         // User2 tries to add User1 as a contact.
472         \core_message\api::create_contact_request($user2->id, $user1->id);
474         // Verify we don't see the contact request from the blocked user User2 in the requests for User1.
475         $this->setUser($user1);
476         $requests = core_message_external::get_contact_requests($user1->id);
477         $requests = external_api::clean_returnvalue(core_message_external::get_contact_requests_returns(), $requests);
479         $this->assertCount(0, $requests);
480     }
482     /**
483      * Test getting contact requests when there are none.
484      */
485     public function test_get_contact_requests_no_requests() {
486         $this->resetAfterTest();
488         $user1 = self::getDataGenerator()->create_user();
490         $this->setUser($user1);
492         $requests = core_message_external::get_contact_requests($user1->id);
493         $requests = external_api::clean_returnvalue(core_message_external::get_contact_requests_returns(), $requests);
495         $this->assertEmpty($requests);
496     }
498     /**
499      * Test getting contact requests with limits.
500      */
501     public function test_get_contact_requests_with_limits() {
502         $this->resetAfterTest();
504         $user1 = self::getDataGenerator()->create_user();
505         $user2 = self::getDataGenerator()->create_user();
506         $user3 = self::getDataGenerator()->create_user();
508         $this->setUser($user1);
510         \core_message\api::create_contact_request($user2->id, $user1->id);
511         \core_message\api::create_contact_request($user3->id, $user1->id);
513         $requests = core_message_external::get_contact_requests($user1->id, 0, 1);
514         $requests = external_api::clean_returnvalue(core_message_external::get_contact_requests_returns(), $requests);
516         $this->assertCount(1, $requests);
517     }
519     /**
520      * Test getting contact requests with messaging disabled.
521      */
522     public function test_get_contact_requests_messaging_disabled() {
523         global $CFG;
525         $this->resetAfterTest();
527         // Create some skeleton data just so we can call the WS.
528         $user1 = self::getDataGenerator()->create_user();
530         $this->setUser($user1);
532         // Disable messaging.
533         $CFG->messaging = 0;
535         // Ensure an exception is thrown.
536         $this->expectException('moodle_exception');
537         core_message_external::get_contact_requests($user1->id);
538     }
540     /**
541      * Test getting contact requests with no permission.
542      */
543     public function test_get_contact_requests_no_permission() {
544         $this->resetAfterTest();
546         // Create some skeleton data just so we can call the WS.
547         $user1 = self::getDataGenerator()->create_user();
548         $user2 = self::getDataGenerator()->create_user();
549         $user3 = self::getDataGenerator()->create_user();
551         $this->setUser($user3);
553         // Ensure an exception is thrown.
554         $this->expectException('required_capability_exception');
555         core_message_external::create_contact_request($user1->id, $user2->id);
556     }
558     /**
559      * Test getting the number of received contact requests.
560      */
561     public function test_get_received_contact_requests_count() {
562         $this->resetAfterTest();
564         $user1 = self::getDataGenerator()->create_user();
565         $user2 = self::getDataGenerator()->create_user();
566         $user3 = self::getDataGenerator()->create_user();
567         $user4 = self::getDataGenerator()->create_user();
569         $this->setUser($user1);
571         $contactrequestnumber = core_message_external::get_received_contact_requests_count($user1->id);
572         $contactrequestnumber = external_api::clean_returnvalue(
573             core_message_external::get_received_contact_requests_count_returns(), $contactrequestnumber);
574         $this->assertEquals(0, $contactrequestnumber);
576         \core_message\api::create_contact_request($user2->id, $user1->id);
578         $contactrequestnumber = core_message_external::get_received_contact_requests_count($user1->id);
579         $contactrequestnumber = external_api::clean_returnvalue(
580             core_message_external::get_received_contact_requests_count_returns(), $contactrequestnumber);
581         $this->assertEquals(1, $contactrequestnumber);
583         \core_message\api::create_contact_request($user3->id, $user1->id);
585         $contactrequestnumber = core_message_external::get_received_contact_requests_count($user1->id);
586         $contactrequestnumber = external_api::clean_returnvalue(
587             core_message_external::get_received_contact_requests_count_returns(), $contactrequestnumber);
588         $this->assertEquals(2, $contactrequestnumber);
590         \core_message\api::create_contact_request($user1->id, $user4->id);
592         // Web service should ignore sent requests.
593         $contactrequestnumber = core_message_external::get_received_contact_requests_count($user1->id);
594         $contactrequestnumber = external_api::clean_returnvalue(
595             core_message_external::get_received_contact_requests_count_returns(), $contactrequestnumber);
596         $this->assertEquals(2, $contactrequestnumber);
597     }
599     /**
600      * Test the get_received_contact_requests_count() function when the user has blocked the sender of the request.
601      */
602     public function test_get_received_contact_requests_count_blocked_sender() {
603         $this->resetAfterTest();
604         $user1 = self::getDataGenerator()->create_user();
605         $user2 = self::getDataGenerator()->create_user();
607         // User1 blocks User2.
608         \core_message\api::block_user($user1->id, $user2->id);
610         // User2 tries to add User1 as a contact.
611         \core_message\api::create_contact_request($user2->id, $user1->id);
613         // Verify we don't see the contact request from the blocked user User2 in the count for User1.
614         $this->setUser($user1);
615         $contactrequestnumber = core_message_external::get_received_contact_requests_count($user1->id);
616         $contactrequestnumber = external_api::clean_returnvalue(
617             core_message_external::get_received_contact_requests_count_returns(), $contactrequestnumber);
618         $this->assertEquals(0, $contactrequestnumber);
619     }
621     /**
622      * Test getting the number of received contact requests with no permissions.
623      */
624     public function test_get_received_contact_requests_count_no_permission() {
625         $this->resetAfterTest();
627         // Create some skeleton data just so we can call the WS.
628         $user1 = self::getDataGenerator()->create_user();
629         $user2 = self::getDataGenerator()->create_user();
631         $this->setUser($user2);
633         // Ensure an exception is thrown.
634         $this->expectException('required_capability_exception');
635         core_message_external::get_received_contact_requests_count($user1->id);
636     }
638     /**
639      * Test getting the number of received contact requests with messaging disabled.
640      */
641     public function test_get_received_contact_requests_count_messaging_disabled() {
642         global $CFG;
644         $this->resetAfterTest();
646         // Create some skeleton data just so we can call the WS.
647         $user1 = self::getDataGenerator()->create_user();
649         $this->setUser($user1);
651         // Disable messaging.
652         $CFG->messaging = 0;
654         // Ensure an exception is thrown.
655         $this->expectException('moodle_exception');
656         core_message_external::get_received_contact_requests_count($user1->id);
657     }
659     /**
660      * Test creating a contact request.
661      */
662     public function test_create_contact_request() {
663         global $CFG, $DB;
665         $this->resetAfterTest();
667         $user1 = self::getDataGenerator()->create_user();
668         $user2 = self::getDataGenerator()->create_user();
670         $this->setUser($user1);
672         // Allow users to message anyone site-wide.
673         $CFG->messagingallusers = 1;
675         $return = core_message_external::create_contact_request($user1->id, $user2->id);
676         $return = external_api::clean_returnvalue(core_message_external::create_contact_request_returns(), $return);
677         $this->assertEquals([], $return['warnings']);
679         $request = $DB->get_records('message_contact_requests');
681         $this->assertCount(1, $request);
683         $request = reset($request);
685         $this->assertEquals($request->id, $return['request']['id']);
686         $this->assertEquals($request->userid, $return['request']['userid']);
687         $this->assertEquals($request->requesteduserid, $return['request']['requesteduserid']);
688         $this->assertEquals($request->timecreated, $return['request']['timecreated']);
689     }
691     /**
692      * Test creating a contact request when not allowed.
693      */
694     public function test_create_contact_request_not_allowed() {
695         global $CFG;
697         $this->resetAfterTest();
699         $user1 = self::getDataGenerator()->create_user();
700         $user2 = self::getDataGenerator()->create_user();
702         $this->setUser($user1);
704         $CFG->messagingallusers = 0;
706         $return = core_message_external::create_contact_request($user1->id, $user2->id);
707         $return = external_api::clean_returnvalue(core_message_external::create_contact_request_returns(), $return);
709         $warning = reset($return['warnings']);
711         $this->assertEquals('user', $warning['item']);
712         $this->assertEquals($user2->id, $warning['itemid']);
713         $this->assertEquals('cannotcreatecontactrequest', $warning['warningcode']);
714         $this->assertEquals('You are unable to create a contact request for this user', $warning['message']);
715     }
717     /**
718      * Test creating a contact request with messaging disabled.
719      */
720     public function test_create_contact_request_messaging_disabled() {
721         global $CFG;
723         $this->resetAfterTest();
725         // Create some skeleton data just so we can call the WS.
726         $user1 = self::getDataGenerator()->create_user();
727         $user2 = self::getDataGenerator()->create_user();
729         $this->setUser($user1);
731         // Disable messaging.
732         $CFG->messaging = 0;
734         // Ensure an exception is thrown.
735         $this->expectException('moodle_exception');
736         core_message_external::create_contact_request($user1->id, $user2->id);
737     }
739     /**
740      * Test creating a contact request with no permission.
741      */
742     public function test_create_contact_request_no_permission() {
743         $this->resetAfterTest();
745         // Create some skeleton data just so we can call the WS.
746         $user1 = self::getDataGenerator()->create_user();
747         $user2 = self::getDataGenerator()->create_user();
748         $user3 = self::getDataGenerator()->create_user();
750         $this->setUser($user3);
752         // Ensure an exception is thrown.
753         $this->expectException('required_capability_exception');
754         core_message_external::create_contact_request($user1->id, $user2->id);
755     }
757     /**
758      * Test confirming a contact request.
759      */
760     public function test_confirm_contact_request() {
761         global $DB;
763         $this->resetAfterTest();
765         $user1 = self::getDataGenerator()->create_user();
766         $user2 = self::getDataGenerator()->create_user();
768         $this->setUser($user1);
770         \core_message\api::create_contact_request($user1->id, $user2->id);
772         $this->setUser($user2);
774         $return = core_message_external::confirm_contact_request($user1->id, $user2->id);
775         $return = external_api::clean_returnvalue(core_message_external::confirm_contact_request_returns(), $return);
776         $this->assertEquals(array(), $return);
778         $this->assertEquals(0, $DB->count_records('message_contact_requests'));
780         $contact = $DB->get_records('message_contacts');
782         $this->assertCount(1, $contact);
784         $contact = reset($contact);
786         $this->assertEquals($user1->id, $contact->userid);
787         $this->assertEquals($user2->id, $contact->contactid);
788     }
790     /**
791      * Test confirming a contact request with messaging disabled.
792      */
793     public function test_confirm_contact_request_messaging_disabled() {
794         global $CFG;
796         $this->resetAfterTest();
798         // Create some skeleton data just so we can call the WS.
799         $user1 = self::getDataGenerator()->create_user();
800         $user2 = self::getDataGenerator()->create_user();
802         $this->setUser($user1);
804         // Disable messaging.
805         $CFG->messaging = 0;
807         // Ensure an exception is thrown.
808         $this->expectException('moodle_exception');
809         core_message_external::confirm_contact_request($user1->id, $user2->id);
810     }
812     /**
813      * Test confirming a contact request with no permission.
814      */
815     public function test_confirm_contact_request_no_permission() {
816         $this->resetAfterTest();
818         // Create some skeleton data just so we can call the WS.
819         $user1 = self::getDataGenerator()->create_user();
820         $user2 = self::getDataGenerator()->create_user();
821         $user3 = self::getDataGenerator()->create_user();
823         $this->setUser($user3);
825         // Ensure an exception is thrown.
826         $this->expectException('required_capability_exception');
827         core_message_external::confirm_contact_request($user1->id, $user2->id);
828     }
830     /**
831      * Test declining a contact request.
832      */
833     public function test_decline_contact_request() {
834         global $DB;
836         $this->resetAfterTest();
838         $user1 = self::getDataGenerator()->create_user();
839         $user2 = self::getDataGenerator()->create_user();
841         $this->setUser($user1);
843         \core_message\api::create_contact_request($user1->id, $user2->id);
845         $this->setUser($user2);
847         $return = core_message_external::decline_contact_request($user1->id, $user2->id);
848         $return = external_api::clean_returnvalue(core_message_external::decline_contact_request_returns(), $return);
849         $this->assertEquals(array(), $return);
851         $this->assertEquals(0, $DB->count_records('message_contact_requests'));
852         $this->assertEquals(0, $DB->count_records('message_contacts'));
853     }
855     /**
856      * Test declining a contact request with messaging disabled.
857      */
858     public function test_decline_contact_request_messaging_disabled() {
859         global $CFG;
861         $this->resetAfterTest();
863         // Create some skeleton data just so we can call the WS.
864         $user1 = self::getDataGenerator()->create_user();
865         $user2 = self::getDataGenerator()->create_user();
867         $this->setUser($user1);
869         // Disable messaging.
870         $CFG->messaging = 0;
872         // Ensure an exception is thrown.
873         $this->expectException('moodle_exception');
874         core_message_external::decline_contact_request($user1->id, $user2->id);
875     }
877     /**
878      * Test declining a contact request with no permission.
879      */
880     public function test_decline_contact_request_no_permission() {
881         $this->resetAfterTest();
883         // Create some skeleton data just so we can call the WS.
884         $user1 = self::getDataGenerator()->create_user();
885         $user2 = self::getDataGenerator()->create_user();
886         $user3 = self::getDataGenerator()->create_user();
888         $this->setUser($user3);
890         // Ensure an exception is thrown.
891         $this->expectException('required_capability_exception');
892         core_message_external::decline_contact_request($user1->id, $user2->id);
893     }
895     /**
896      * Test muting conversations.
897      */
898     public function test_mute_conversations() {
899         global $DB;
901         $this->resetAfterTest(true);
903         $user1 = self::getDataGenerator()->create_user();
904         $user2 = self::getDataGenerator()->create_user();
906         $conversation = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
907             [$user1->id, $user2->id]);
909         $this->setUser($user1);
911         // Muting a conversation.
912         $return = core_message_external::mute_conversations($user1->id, [$conversation->id]);
913         $return = external_api::clean_returnvalue(core_message_external::mute_conversations_returns(), $return);
914         $this->assertEquals(array(), $return);
916         // Get list of muted conversations.
917         $mca = $DB->get_record('message_conversation_actions', []);
919         $this->assertEquals($user1->id, $mca->userid);
920         $this->assertEquals($conversation->id, $mca->conversationid);
921         $this->assertEquals(\core_message\api::CONVERSATION_ACTION_MUTED, $mca->action);
923         // Muting a conversation that is already muted.
924         $return = core_message_external::mute_conversations($user1->id, [$conversation->id]);
925         $return = external_api::clean_returnvalue(core_message_external::mute_conversations_returns(), $return);
926         $this->assertEquals(array(), $return);
928         $this->assertEquals(1, $DB->count_records('message_conversation_actions'));
929     }
931     /**
932      * Test muting a conversation with messaging disabled.
933      */
934     public function test_mute_conversations_messaging_disabled() {
935         global $CFG;
937         $this->resetAfterTest();
939         // Create some skeleton data just so we can call the WS.
940         $user1 = self::getDataGenerator()->create_user();
941         $user2 = self::getDataGenerator()->create_user();
943         $conversation = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
944             [$user1->id, $user2->id]);
946         $this->setUser($user1);
948         // Disable messaging.
949         $CFG->messaging = 0;
951         // Ensure an exception is thrown.
952         $this->expectException('moodle_exception');
953         core_message_external::mute_conversations($user1->id, [$conversation->id]);
954     }
956     /**
957      * Test muting a conversation with no permission.
958      */
959     public function test_mute_conversations_no_permission() {
960         $this->resetAfterTest();
962         // Create some skeleton data just so we can call the WS.
963         $user1 = self::getDataGenerator()->create_user();
964         $user2 = self::getDataGenerator()->create_user();
965         $user3 = self::getDataGenerator()->create_user();
967         $conversation = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
968             [$user1->id, $user2->id]);
970         $this->setUser($user3);
972         // Ensure an exception is thrown.
973         $this->expectException('required_capability_exception');
974         core_message_external::mute_conversations($user1->id, [$conversation->id]);
975     }
977     /**
978      * Test unmuting conversations.
979      */
980     public function test_unmute_conversations() {
981         global $DB;
983         $this->resetAfterTest(true);
985         $user1 = self::getDataGenerator()->create_user();
986         $user2 = self::getDataGenerator()->create_user();
988         $conversation = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
989             [$user1->id, $user2->id]);
991         $this->setUser($user1);
993         // Mute the conversation.
994         \core_message\api::mute_conversation($user1->id, $conversation->id);
996         // Unmuting a conversation.
997         $return = core_message_external::unmute_conversations($user1->id, [$conversation->id]);
998         $return = external_api::clean_returnvalue(core_message_external::unmute_conversations_returns(), $return);
999         $this->assertEquals(array(), $return);
1001         $this->assertEquals(0, $DB->count_records('message_conversation_actions'));
1003         // Unmuting a conversation which is already unmuted.
1004         $return = core_message_external::unmute_conversations($user1->id, [$conversation->id]);
1005         $return = external_api::clean_returnvalue(core_message_external::unmute_conversations_returns(), $return);
1006         $this->assertEquals(array(), $return);
1008         $this->assertEquals(0, $DB->count_records('message_conversation_actions'));
1009     }
1011     /**
1012      * Test unmuting a conversation with messaging disabled.
1013      */
1014     public function test_unmute_conversation_messaging_disabled() {
1015         global $CFG;
1017         $this->resetAfterTest();
1019         // Create some skeleton data just so we can call the WS.
1020         $user1 = self::getDataGenerator()->create_user();
1021         $user2 = self::getDataGenerator()->create_user();
1023         $conversation = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1024             [$user1->id, $user2->id]);
1026         $this->setUser($user1);
1028         // Disable messaging.
1029         $CFG->messaging = 0;
1031         // Ensure an exception is thrown.
1032         $this->expectException('moodle_exception');
1033         core_message_external::unmute_conversations($user1->id, [$user2->id]);
1034     }
1036     /**
1037      * Test unmuting a conversation with no permission.
1038      */
1039     public function test_unmute_conversation_no_permission() {
1040         $this->resetAfterTest();
1042         // Create some skeleton data just so we can call the WS.
1043         $user1 = self::getDataGenerator()->create_user();
1044         $user2 = self::getDataGenerator()->create_user();
1045         $user3 = self::getDataGenerator()->create_user();
1047         $conversation = \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
1048             [$user1->id, $user2->id]);
1050         $this->setUser($user3);
1052         // Ensure an exception is thrown.
1053         $this->expectException('required_capability_exception');
1054         core_message_external::unmute_conversations($user1->id, [$conversation->id]);
1055     }
1057     /**
1058      * Test blocking a user.
1059      */
1060     public function test_block_user() {
1061         global $DB;
1063         $this->resetAfterTest(true);
1065         $user1 = self::getDataGenerator()->create_user();
1066         $user2 = self::getDataGenerator()->create_user();
1068         $this->setUser($user1);
1070         // Blocking a user.
1071         $return = core_message_external::block_user($user1->id, $user2->id);
1072         $return = external_api::clean_returnvalue(core_message_external::block_user_returns(), $return);
1073         $this->assertEquals(array(), $return);
1075         // Get list of blocked users.
1076         $record = $DB->get_record('message_users_blocked', []);
1078         $this->assertEquals($user1->id, $record->userid);
1079         $this->assertEquals($user2->id, $record->blockeduserid);
1081         // Blocking a user who is already blocked.
1082         $return = core_message_external::block_user($user1->id, $user2->id);
1083         $return = external_api::clean_returnvalue(core_message_external::block_user_returns(), $return);
1084         $this->assertEquals(array(), $return);
1086         $this->assertEquals(1, $DB->count_records('message_users_blocked'));
1087     }
1089     /**
1090      * Test blocking a user.
1091      */
1092     public function test_block_user_when_ineffective() {
1093         global $DB;
1095         $this->resetAfterTest(true);
1097         $user1 = self::getDataGenerator()->create_user();
1098         $user2 = self::getDataGenerator()->create_user();
1100         $this->setUser($user1);
1102         $authenticateduser = $DB->get_record('role', array('shortname' => 'user'));
1103         assign_capability('moodle/site:messageanyuser', CAP_ALLOW, $authenticateduser->id, context_system::instance(), true);
1105         // Blocking a user.
1106         $return = core_message_external::block_user($user1->id, $user2->id);
1107         $return = external_api::clean_returnvalue(core_message_external::block_user_returns(), $return);
1108         $this->assertEquals(array(), $return);
1110         $this->assertEquals(0, $DB->count_records('message_users_blocked'));
1111     }
1113     /**
1114      * Test blocking a user with messaging disabled.
1115      */
1116     public function test_block_user_messaging_disabled() {
1117         global $CFG;
1119         $this->resetAfterTest();
1121         // Create some skeleton data just so we can call the WS.
1122         $user1 = self::getDataGenerator()->create_user();
1123         $user2 = self::getDataGenerator()->create_user();
1125         $this->setUser($user1);
1127         // Disable messaging.
1128         $CFG->messaging = 0;
1130         // Ensure an exception is thrown.
1131         $this->expectException('moodle_exception');
1132         core_message_external::block_user($user1->id, $user2->id);
1133     }
1135     /**
1136      * Test blocking a user with no permission.
1137      */
1138     public function test_block_user_no_permission() {
1139         $this->resetAfterTest();
1141         // Create some skeleton data just so we can call the WS.
1142         $user1 = self::getDataGenerator()->create_user();
1143         $user2 = self::getDataGenerator()->create_user();
1144         $user3 = self::getDataGenerator()->create_user();
1146         $this->setUser($user3);
1148         // Ensure an exception is thrown.
1149         $this->expectException('required_capability_exception');
1150         core_message_external::block_user($user1->id, $user2->id);
1151     }
1153     /**
1154      * Test unblocking a user.
1155      */
1156     public function test_unblock_user() {
1157         global $DB;
1159         $this->resetAfterTest(true);
1161         $user1 = self::getDataGenerator()->create_user();
1162         $user2 = self::getDataGenerator()->create_user();
1164         $this->setUser($user1);
1166         // Block the user.
1167         \core_message\api::block_user($user1->id, $user2->id);
1169         // Unblocking a user.
1170         $return = core_message_external::unblock_user($user1->id, $user2->id);
1171         $return = external_api::clean_returnvalue(core_message_external::unblock_user_returns(), $return);
1172         $this->assertEquals(array(), $return);
1174         $this->assertEquals(0, $DB->count_records('message_users_blocked'));
1176         // Unblocking a user who is already unblocked.
1177         $return = core_message_external::unblock_user($user1->id, $user2->id);
1178         $return = external_api::clean_returnvalue(core_message_external::unblock_user_returns(), $return);
1179         $this->assertEquals(array(), $return);
1181         $this->assertEquals(0, $DB->count_records('message_users_blocked'));
1182     }
1184     /**
1185      * Test unblocking a user with messaging disabled.
1186      */
1187     public function test_unblock_user_messaging_disabled() {
1188         global $CFG;
1190         $this->resetAfterTest();
1192         // Create some skeleton data just so we can call the WS.
1193         $user1 = self::getDataGenerator()->create_user();
1194         $user2 = self::getDataGenerator()->create_user();
1196         $this->setUser($user1);
1198         // Disable messaging.
1199         $CFG->messaging = 0;
1201         // Ensure an exception is thrown.
1202         $this->expectException('moodle_exception');
1203         core_message_external::unblock_user($user1->id, $user2->id);
1204     }
1206     /**
1207      * Test unblocking a user with no permission.
1208      */
1209     public function test_unblock_user_no_permission() {
1210         $this->resetAfterTest();
1212         // Create some skeleton data just so we can call the WS.
1213         $user1 = self::getDataGenerator()->create_user();
1214         $user2 = self::getDataGenerator()->create_user();
1215         $user3 = self::getDataGenerator()->create_user();
1217         $this->setUser($user3);
1219         // Ensure an exception is thrown.
1220         $this->expectException('required_capability_exception');
1221         core_message_external::unblock_user($user1->id, $user2->id);
1222     }
1224     /**
1225      * Test search_contacts.
1226      */
1227     public function test_search_contacts() {
1228         global $DB;
1229         $this->resetAfterTest(true);
1231         $course1 = $this->getDataGenerator()->create_course();
1232         $course2 = $this->getDataGenerator()->create_course();
1234         $user1 = new stdClass();
1235         $user1->firstname = 'X';
1236         $user1->lastname = 'X';
1237         $user1 = $this->getDataGenerator()->create_user($user1);
1238         $this->getDataGenerator()->enrol_user($user1->id, $course1->id);
1239         $this->getDataGenerator()->enrol_user($user1->id, $course2->id);
1241         $user2 = new stdClass();
1242         $user2->firstname = 'Eric';
1243         $user2->lastname = 'Cartman';
1244         $user2 = self::getDataGenerator()->create_user($user2);
1245         $user3 = new stdClass();
1246         $user3->firstname = 'Stan';
1247         $user3->lastname = 'Marsh';
1248         $user3 = self::getDataGenerator()->create_user($user3);
1249         self::getDataGenerator()->enrol_user($user3->id, $course1->id);
1250         $user4 = new stdClass();
1251         $user4->firstname = 'Kyle';
1252         $user4->lastname = 'Broflovski';
1253         $user4 = self::getDataGenerator()->create_user($user4);
1254         $user5 = new stdClass();
1255         $user5->firstname = 'Kenny';
1256         $user5->lastname = 'McCormick';
1257         $user5 = self::getDataGenerator()->create_user($user5);
1258         self::getDataGenerator()->enrol_user($user5->id, $course2->id);
1260         $this->setUser($user1);
1262         $results = core_message_external::search_contacts('r');
1263         $results = external_api::clean_returnvalue(core_message_external::search_contacts_returns(), $results);
1264         $this->assertCount(5, $results); // Users 2 through 5 + admin
1266         $results = core_message_external::search_contacts('r', true);
1267         $results = external_api::clean_returnvalue(core_message_external::search_contacts_returns(), $results);
1268         $this->assertCount(2, $results);
1270         $results = core_message_external::search_contacts('Kyle', false);
1271         $results = external_api::clean_returnvalue(core_message_external::search_contacts_returns(), $results);
1272         $this->assertCount(1, $results);
1273         $result = reset($results);
1274         $this->assertEquals($user4->id, $result['id']);
1276         $results = core_message_external::search_contacts('y', false);
1277         $results = external_api::clean_returnvalue(core_message_external::search_contacts_returns(), $results);
1278         $this->assertCount(2, $results);
1280         $results = core_message_external::search_contacts('y', true);
1281         $results = external_api::clean_returnvalue(core_message_external::search_contacts_returns(), $results);
1282         $this->assertCount(1, $results);
1283         $result = reset($results);
1284         $this->assertEquals($user5->id, $result['id']);
1286         // Empty query, will throw an exception.
1287         $this->expectException(moodle_exception::class);
1288         $results = core_message_external::search_contacts('');
1289     }
1291     /**
1292      * Test get_messages.
1293      */
1294     public function test_get_messages() {
1295         global $CFG, $DB;
1296         $this->resetAfterTest(true);
1298         $this->preventResetByRollback();
1299         // This mark the messages as read!.
1300         $sink = $this->redirectMessages();
1302         $user1 = self::getDataGenerator()->create_user();
1303         $user2 = self::getDataGenerator()->create_user();
1304         $user3 = self::getDataGenerator()->create_user();
1306         $course = self::getDataGenerator()->create_course();
1308         // Send a message from one user to another.
1309         message_post_message($user1, $user2, 'some random text 1', FORMAT_MOODLE);
1310         message_post_message($user1, $user3, 'some random text 2', FORMAT_MOODLE);
1311         message_post_message($user2, $user3, 'some random text 3', FORMAT_MOODLE);
1312         message_post_message($user3, $user2, 'some random text 4', FORMAT_MOODLE);
1313         message_post_message($user3, $user1, 'some random text 5', FORMAT_MOODLE);
1315         $this->setUser($user1);
1316         // Get read conversations from user1 to user2.
1317         $messages = core_message_external::get_messages($user2->id, $user1->id, 'conversations', true, true, 0, 0);
1318         $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
1319         $this->assertCount(1, $messages['messages']);
1321         // Delete the message.
1322         $message = array_shift($messages['messages']);
1323         \core_message\api::delete_message($user1->id, $message['id']);
1325         $messages = core_message_external::get_messages($user2->id, $user1->id, 'conversations', true, true, 0, 0);
1326         $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
1327         $this->assertCount(0, $messages['messages']);
1329         // Get unread conversations from user1 to user2.
1330         $messages = core_message_external::get_messages($user2->id, $user1->id, 'conversations', false, true, 0, 0);
1331         $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
1332         $this->assertCount(0, $messages['messages']);
1334         // Get read messages send from user1.
1335         $messages = core_message_external::get_messages(0, $user1->id, 'conversations', true, true, 0, 0);
1336         $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
1337         $this->assertCount(1, $messages['messages']);
1339         $this->setUser($user2);
1340         // Get read conversations from any user to user2.
1341         $messages = core_message_external::get_messages($user2->id, 0, 'conversations', true, true, 0, 0);
1342         $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
1343         $this->assertCount(2, $messages['messages']);
1345         // Conversations from user3 to user2.
1346         $messages = core_message_external::get_messages($user2->id, $user3->id, 'conversations', true, true, 0, 0);
1347         $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
1348         $this->assertCount(1, $messages['messages']);
1350         // Delete the message.
1351         $message = array_shift($messages['messages']);
1352         \core_message\api::delete_message($user2->id, $message['id']);
1354         $messages = core_message_external::get_messages($user2->id, $user3->id, 'conversations', true, true, 0, 0);
1355         $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
1356         $this->assertCount(0, $messages['messages']);
1358         $this->setUser($user3);
1359         // Get read notifications received by user3.
1360         $messages = core_message_external::get_messages($user3->id, 0, 'notifications', true, true, 0, 0);
1361         $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
1362         $this->assertCount(0, $messages['messages']);
1364         // Now, create some notifications...
1365         // We are creating fake notifications but based on real ones.
1367         // This one comes from a disabled plugin's provider and therefore is not sent.
1368         $eventdata = new \core\message\message();
1369         $eventdata->courseid          = $course->id;
1370         $eventdata->notification      = 1;
1371         $eventdata->modulename        = 'moodle';
1372         $eventdata->component         = 'enrol_paypal';
1373         $eventdata->name              = 'paypal_enrolment';
1374         $eventdata->userfrom          = get_admin();
1375         $eventdata->userto            = $user1;
1376         $eventdata->subject           = "Moodle: PayPal payment";
1377         $eventdata->fullmessage       = "Your PayPal payment is pending.";
1378         $eventdata->fullmessageformat = FORMAT_PLAIN;
1379         $eventdata->fullmessagehtml   = '';
1380         $eventdata->smallmessage      = '';
1381         message_send($eventdata);
1382         $this->assertDebuggingCalled('Attempt to send msg from a provider enrol_paypal/paypal_enrolment '.
1383             'that is inactive or not allowed for the user id='.$user1->id);
1385         // This one omits notification = 1.
1386         $message = new \core\message\message();
1387         $message->courseid          = $course->id;
1388         $message->component         = 'enrol_manual';
1389         $message->name              = 'expiry_notification';
1390         $message->userfrom          = $user2;
1391         $message->userto            = $user1;
1392         $message->subject           = 'Test: This is not a notification but otherwise is valid';
1393         $message->fullmessage       = 'Test: Full message';
1394         $message->fullmessageformat = FORMAT_MARKDOWN;
1395         $message->fullmessagehtml   = markdown_to_html($message->fullmessage);
1396         $message->smallmessage      = $message->subject;
1397         $message->contexturlname    = $course->fullname;
1398         $message->contexturl        = (string)new moodle_url('/course/view.php', array('id' => $course->id));
1399         message_send($message);
1401         $message = new \core\message\message();
1402         $message->courseid          = $course->id;
1403         $message->notification      = 1;
1404         $message->component         = 'enrol_manual';
1405         $message->name              = 'expiry_notification';
1406         $message->userfrom          = $user2;
1407         $message->userto            = $user1;
1408         $message->subject           = 'Enrolment expired';
1409         $message->fullmessage       = 'Enrolment expired blah blah blah';
1410         $message->fullmessageformat = FORMAT_MARKDOWN;
1411         $message->fullmessagehtml   = markdown_to_html($message->fullmessage);
1412         $message->smallmessage      = $message->subject;
1413         $message->contexturlname    = $course->fullname;
1414         $message->contexturl        = (string)new moodle_url('/course/view.php', array('id' => $course->id));
1415         message_send($message);
1417         $userfrom = core_user::get_noreply_user();
1418         $userfrom->maildisplay = true;
1419         $eventdata = new \core\message\message();
1420         $eventdata->courseid          = $course->id;
1421         $eventdata->component         = 'moodle';
1422         $eventdata->name              = 'badgecreatornotice';
1423         $eventdata->userfrom          = $userfrom;
1424         $eventdata->userto            = $user1;
1425         $eventdata->notification      = 1;
1426         $eventdata->subject           = 'New badge';
1427         $eventdata->fullmessage       = format_text_email($eventdata->subject, FORMAT_HTML);
1428         $eventdata->fullmessageformat = FORMAT_PLAIN;
1429         $eventdata->fullmessagehtml   = $eventdata->subject;
1430         $eventdata->smallmessage      = $eventdata->subject;
1431         message_send($eventdata);
1433         $eventdata = new \core\message\message();
1434         $eventdata->courseid         = $course->id;
1435         $eventdata->name             = 'submission';
1436         $eventdata->component        = 'mod_feedback';
1437         $eventdata->userfrom         = $user1;
1438         $eventdata->userto           = $user2;
1439         $eventdata->subject          = 'Feedback submitted';
1440         $eventdata->fullmessage      = 'Feedback submitted from an user';
1441         $eventdata->fullmessageformat = FORMAT_PLAIN;
1442         $eventdata->fullmessagehtml  = '<strong>Feedback submitted</strong>';
1443         $eventdata->smallmessage     = '';
1444         $eventdata->customdata         = ['datakey' => 'data'];
1445         message_send($eventdata);
1447         $this->setUser($user1);
1448         // Get read notifications from any user to user1.
1449         $messages = core_message_external::get_messages($user1->id, 0, 'notifications', true, true, 0, 0);
1450         $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
1451         $this->assertCount(3, $messages['messages']);
1453         // Get one read notifications from any user to user1.
1454         $messages = core_message_external::get_messages($user1->id, 0, 'notifications', true, true, 0, 1);
1455         $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
1456         $this->assertCount(1, $messages['messages']);
1458         // Get unread notifications from any user to user1.
1459         $messages = core_message_external::get_messages($user1->id, 0, 'notifications', false, true, 0, 0);
1460         $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
1461         $this->assertCount(0, $messages['messages']);
1463         // Get read both type of messages from any user to user1.
1464         $messages = core_message_external::get_messages($user1->id, 0, 'both', true, true, 0, 0);
1465         $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
1466         $this->assertCount(4, $messages['messages']);
1468         // Get read notifications from no-reply-user to user1.
1469         $messages = core_message_external::get_messages($user1->id, $userfrom->id, 'notifications', true, true, 0, 0);
1470         $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
1471         $this->assertCount(1, $messages['messages']);
1473         // Get notifications send by user1 to any user.
1474         $messages = core_message_external::get_messages(0, $user1->id, 'notifications', true, true, 0, 0);
1475         $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
1476         $this->assertCount(1, $messages['messages']);
1477         // Check we receive custom data as a unserialisable json.
1478         $this->assertObjectHasAttribute('datakey', json_decode($messages['messages'][0]['customdata']));
1479         $this->assertEquals('mod_feedback', $messages['messages'][0]['component']);
1480         $this->assertEquals('submission', $messages['messages'][0]['eventtype']);
1482         // Test warnings.
1483         $CFG->messaging = 0;
1485         $messages = core_message_external::get_messages(0, $user1->id, 'both', true, true, 0, 0);
1486         $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
1487         $this->assertCount(1, $messages['warnings']);
1489         // Test exceptions.
1491         // Messaging disabled.
1492         try {
1493             $messages = core_message_external::get_messages(0, $user1->id, 'conversations', true, true, 0, 0);
1494             $this->fail('Exception expected due messaging disabled.');
1495         } catch (moodle_exception $e) {
1496             $this->assertEquals('disabled', $e->errorcode);
1497         }
1499         $CFG->messaging = 1;
1501         // Invalid users.
1502         try {
1503             $messages = core_message_external::get_messages(0, 0, 'conversations', true, true, 0, 0);
1504             $this->fail('Exception expected due invalid users.');
1505         } catch (moodle_exception $e) {
1506             $this->assertEquals('accessdenied', $e->errorcode);
1507         }
1509         // Invalid user ids.
1510         try {
1511             $messages = core_message_external::get_messages(2500, 0, 'conversations', true, true, 0, 0);
1512             $this->fail('Exception expected due invalid users.');
1513         } catch (moodle_exception $e) {
1514             $this->assertEquals('invaliduser', $e->errorcode);
1515         }
1517         // Invalid users (permissions).
1518         $this->setUser($user2);
1519         try {
1520             $messages = core_message_external::get_messages(0, $user1->id, 'conversations', true, true, 0, 0);
1521             $this->fail('Exception expected due invalid user.');
1522         } catch (moodle_exception $e) {
1523             $this->assertEquals('accessdenied', $e->errorcode);
1524         }
1526     }
1528     /**
1529      * Test get_messages where we want all messages from a user, sent to any user.
1530      */
1531     public function test_get_messages_useridto_all() {
1532         $this->resetAfterTest(true);
1534         $user1 = self::getDataGenerator()->create_user();
1535         $user2 = self::getDataGenerator()->create_user();
1536         $user3 = self::getDataGenerator()->create_user();
1538         $this->setUser($user1);
1540         // Send a message from user 1 to two other users.
1541         $this->send_message($user1, $user2, 'some random text 1', 0, 1);
1542         $this->send_message($user1, $user3, 'some random text 2', 0, 2);
1544         // Get messages sent from user 1.
1545         $messages = core_message_external::get_messages(0, $user1->id, 'conversations', false, false, 0, 0);
1546         $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
1548         // Confirm the data is correct.
1549         $messages = $messages['messages'];
1550         $this->assertCount(2, $messages);
1552         $message1 = array_shift($messages);
1553         $message2 = array_shift($messages);
1555         $this->assertEquals($user1->id, $message1['useridfrom']);
1556         $this->assertEquals($user2->id, $message1['useridto']);
1558         $this->assertEquals($user1->id, $message2['useridfrom']);
1559         $this->assertEquals($user3->id, $message2['useridto']);
1560     }
1562     /**
1563      * Test get_messages where we want all messages to a user, sent by any user.
1564      */
1565     public function test_get_messages_useridfrom_all() {
1566         $this->resetAfterTest();
1568         $user1 = self::getDataGenerator()->create_user();
1569         $user2 = self::getDataGenerator()->create_user();
1570         $user3 = self::getDataGenerator()->create_user();
1572         $this->setUser($user1);
1574         // Send a message to user 1 from two other users.
1575         $this->send_message($user2, $user1, 'some random text 1', 0, 1);
1576         $this->send_message($user3, $user1, 'some random text 2', 0, 2);
1578         // Get messages sent to user 1.
1579         $messages = core_message_external::get_messages($user1->id, 0, 'conversations', false, false, 0, 0);
1580         $messages = external_api::clean_returnvalue(core_message_external::get_messages_returns(), $messages);
1582         // Confirm the data is correct.
1583         $messages = $messages['messages'];
1584         $this->assertCount(2, $messages);
1586         $message1 = array_shift($messages);
1587         $message2 = array_shift($messages);
1589         $this->assertEquals($user2->id, $message1['useridfrom']);
1590         $this->assertEquals($user1->id, $message1['useridto']);
1592         $this->assertEquals($user3->id, $message2['useridfrom']);
1593         $this->assertEquals($user1->id, $message2['useridto']);
1594     }
1596     /**
1597      * Test get_blocked_users.
1598      */
1599     public function test_get_blocked_users() {
1600         $this->resetAfterTest(true);
1602         $user1 = self::getDataGenerator()->create_user();
1603         $userstranger = self::getDataGenerator()->create_user();
1604         $useroffline1 = self::getDataGenerator()->create_user();
1605         $useroffline2 = self::getDataGenerator()->create_user();
1606         $userblocked = self::getDataGenerator()->create_user();
1608         // Login as user1.
1609         $this->setUser($user1);
1611         \core_message\api::add_contact($user1->id, $useroffline1->id);
1612         \core_message\api::add_contact($user1->id, $useroffline2->id);
1614         // The userstranger sends a couple of messages to user1.
1615         $this->send_message($userstranger, $user1, 'Hello there!');
1616         $this->send_message($userstranger, $user1, 'How you goin?');
1618         // The userblocked sends a message to user1.
1619         // Note that this user is not blocked at this point.
1620         $this->send_message($userblocked, $user1, 'Here, have some spam.');
1622         // Retrieve the list of blocked users.
1623         $this->setUser($user1);
1624         $blockedusers = core_message_external::get_blocked_users($user1->id);
1625         $blockedusers = external_api::clean_returnvalue(core_message_external::get_blocked_users_returns(), $blockedusers);
1626         $this->assertCount(0, $blockedusers['users']);
1628         // Block the $userblocked and retrieve again the list.
1629         \core_message\api::block_user($user1->id, $userblocked->id);
1630         $blockedusers = core_message_external::get_blocked_users($user1->id);
1631         $blockedusers = external_api::clean_returnvalue(core_message_external::get_blocked_users_returns(), $blockedusers);
1632         $this->assertCount(1, $blockedusers['users']);
1634         // Remove the $userblocked and check that the list now is empty.
1635         delete_user($userblocked);
1636         $blockedusers = core_message_external::get_blocked_users($user1->id);
1637         $blockedusers = external_api::clean_returnvalue(core_message_external::get_blocked_users_returns(), $blockedusers);
1638         $this->assertCount(0, $blockedusers['users']);
1639     }
1641     /**
1642      * Test mark_message_read.
1643      */
1644     public function test_mark_message_read() {
1645         $this->resetAfterTest(true);
1647         $user1 = self::getDataGenerator()->create_user();
1648         $user2 = self::getDataGenerator()->create_user();
1649         $user3 = self::getDataGenerator()->create_user();
1651         // Login as user1.
1652         $this->setUser($user1);
1653         \core_message\api::add_contact($user1->id, $user2->id);
1654         \core_message\api::add_contact($user1->id, $user3->id);
1656         // The user2 sends a couple of messages to user1.
1657         $this->send_message($user2, $user1, 'Hello there!');
1658         $this->send_message($user2, $user1, 'How you goin?');
1659         $this->send_message($user3, $user1, 'How you goin?');
1660         $this->send_message($user3, $user2, 'How you goin?');
1662         // Retrieve all messages sent by user2 (they are currently unread).
1663         $lastmessages = message_get_messages($user1->id, $user2->id, 0, false);
1665         $messageids = array();
1666         foreach ($lastmessages as $m) {
1667             $messageid = core_message_external::mark_message_read($m->id, time());
1668             $messageids[] = external_api::clean_returnvalue(core_message_external::mark_message_read_returns(), $messageid);
1669         }
1671         // Retrieve all messages sent (they are currently read).
1672         $lastmessages = message_get_messages($user1->id, $user2->id, 0, true);
1673         $this->assertCount(2, $lastmessages);
1674         $this->assertArrayHasKey($messageids[0]['messageid'], $lastmessages);
1675         $this->assertArrayHasKey($messageids[1]['messageid'], $lastmessages);
1677         // Retrieve all messages sent by any user (that are currently unread).
1678         $lastmessages = message_get_messages($user1->id, 0, 0, false);
1679         $this->assertCount(1, $lastmessages);
1681         // Invalid message ids.
1682         try {
1683             $messageid = core_message_external::mark_message_read(1337, time());
1684             $this->fail('Exception expected due invalid messageid.');
1685         } catch (dml_missing_record_exception $e) {
1686             $this->assertEquals('invalidrecordunknown', $e->errorcode);
1687         }
1689         // A message to a different user.
1690         $lastmessages = message_get_messages($user2->id, $user3->id, 0, false);
1691         $messageid = array_pop($lastmessages)->id;
1692         try {
1693             $messageid = core_message_external::mark_message_read($messageid, time());
1694             $this->fail('Exception expected due invalid messageid.');
1695         } catch (invalid_parameter_exception $e) {
1696             $this->assertEquals('invalidparameter', $e->errorcode);
1697         }
1698     }
1700     /**
1701      * Test mark_notification_read.
1702      */
1703     public function test_mark_notification_read() {
1704         $this->resetAfterTest(true);
1706         $user1 = self::getDataGenerator()->create_user();
1707         $user2 = self::getDataGenerator()->create_user();
1708         $user3 = self::getDataGenerator()->create_user();
1710         // Login as user1.
1711         $this->setUser($user1);
1712         \core_message\api::add_contact($user1->id, $user2->id);
1713         \core_message\api::add_contact($user1->id, $user3->id);
1715         // The user2 sends a couple of notifications to user1.
1716         $this->send_message($user2, $user1, 'Hello there!', 1);
1717         $this->send_message($user2, $user1, 'How you goin?', 1);
1718         $this->send_message($user3, $user1, 'How you goin?', 1);
1719         $this->send_message($user3, $user2, 'How you goin?', 1);
1721         // Retrieve all notifications sent by user2 (they are currently unread).
1722         $lastnotifications = message_get_messages($user1->id, $user2->id, 1, false);
1724         $notificationids = array();
1725         foreach ($lastnotifications as $n) {
1726             $notificationid = core_message_external::mark_notification_read($n->id, time());
1727             $notificationids[] = external_api::clean_returnvalue(core_message_external::mark_notification_read_returns(),
1728                 $notificationid);
1729         }
1731         // Retrieve all notifications sent (they are currently read).
1732         $lastnotifications = message_get_messages($user1->id, $user2->id, 1, true);
1733         $this->assertCount(2, $lastnotifications);
1734         $this->assertArrayHasKey($notificationids[1]['notificationid'], $lastnotifications);
1735         $this->assertArrayHasKey($notificationids[0]['notificationid'], $lastnotifications);
1737         // Retrieve all notifications sent by any user (that are currently unread).
1738         $lastnotifications = message_get_messages($user1->id, 0, 1, false);
1739         $this->assertCount(1, $lastnotifications);
1741         // Invalid notification ids.
1742         try {
1743             $notificationid = core_message_external::mark_notification_read(1337, time());
1744             $this->fail('Exception expected due invalid notificationid.');
1745         } catch (dml_missing_record_exception $e) {
1746             $this->assertEquals('invalidrecord', $e->errorcode);
1747         }
1749         // A notification to a different user.
1750         $lastnotifications = message_get_messages($user2->id, $user3->id, 1, false);
1751         $notificationid = array_pop($lastnotifications)->id;
1752         try {
1753             $notificationid = core_message_external::mark_notification_read($notificationid, time());
1754             $this->fail('Exception expected due invalid notificationid.');
1755         } catch (invalid_parameter_exception $e) {
1756             $this->assertEquals('invalidparameter', $e->errorcode);
1757         }
1758     }
1760     /**
1761      * Test delete_message.
1762      */
1763     public function test_delete_message() {
1764         global $DB;
1765         $this->resetAfterTest(true);
1767         $user1 = self::getDataGenerator()->create_user();
1768         $user2 = self::getDataGenerator()->create_user();
1769         $user3 = self::getDataGenerator()->create_user();
1770         $user4 = self::getDataGenerator()->create_user();
1772         // Login as user1.
1773         $this->setUser($user1);
1774         \core_message\api::add_contact($user1->id, $user2->id);
1775         \core_message\api::add_contact($user1->id, $user3->id);
1777         // User user1 does not interchange messages with user3.
1778         $m1to2 = message_post_message($user1, $user2, 'some random text 1', FORMAT_MOODLE);
1779         $m2to3 = message_post_message($user2, $user3, 'some random text 3', FORMAT_MOODLE);
1780         $m3to2 = message_post_message($user3, $user2, 'some random text 4', FORMAT_MOODLE);
1781         $m3to4 = message_post_message($user3, $user4, 'some random text 4', FORMAT_MOODLE);
1783         // Retrieve all messages sent by user2 (they are currently unread).
1784         $lastmessages = message_get_messages($user1->id, $user2->id, 0, false);
1786         // Delete a message not read, as a user from.
1787         $result = core_message_external::delete_message($m1to2, $user1->id, false);
1788         $result = external_api::clean_returnvalue(core_message_external::delete_message_returns(), $result);
1789         $this->assertTrue($result['status']);
1790         $this->assertCount(0, $result['warnings']);
1791         $mua = $DB->get_record('message_user_actions', array('messageid' => $m1to2, 'userid' => $user1->id));
1792         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua->action);
1794         // Try to delete the same message again.
1795         $result = core_message_external::delete_message($m1to2, $user1->id, false);
1796         $result = external_api::clean_returnvalue(core_message_external::delete_message_returns(), $result);
1797         $this->assertFalse($result['status']);
1799         // Try to delete a message that does not belong to me.
1800         try {
1801             $messageid = core_message_external::delete_message($m2to3, $user3->id, false);
1802             $this->fail('Exception expected due invalid messageid.');
1803         } catch (moodle_exception $e) {
1804             $this->assertEquals('You do not have permission to delete this message', $e->errorcode);
1805         }
1807         $this->setUser($user3);
1808         // Delete a message not read, as a user to.
1809         $result = core_message_external::delete_message($m2to3, $user3->id, false);
1810         $result = external_api::clean_returnvalue(core_message_external::delete_message_returns(), $result);
1811         $this->assertTrue($result['status']);
1812         $this->assertCount(0, $result['warnings']);
1813         $this->assertTrue($DB->record_exists('message_user_actions', array('messageid' => $m2to3, 'userid' => $user3->id,
1814             'action' => \core_message\api::MESSAGE_ACTION_DELETED)));
1816         // Delete a message read.
1817         $message = $DB->get_record('messages', ['id' => $m3to2]);
1818         \core_message\api::mark_message_as_read($user3->id, $message, time());
1819         $result = core_message_external::delete_message($m3to2, $user3->id);
1820         $result = external_api::clean_returnvalue(core_message_external::delete_message_returns(), $result);
1821         $this->assertTrue($result['status']);
1822         $this->assertCount(0, $result['warnings']);
1823         $this->assertTrue($DB->record_exists('message_user_actions', array('messageid' => $m3to2, 'userid' => $user3->id,
1824             'action' => \core_message\api::MESSAGE_ACTION_DELETED)));
1826         // Invalid message ids.
1827         try {
1828             $result = core_message_external::delete_message(-1, $user1->id);
1829             $this->fail('Exception expected due invalid messageid.');
1830         } catch (dml_missing_record_exception $e) {
1831             $this->assertEquals('invalidrecord', $e->errorcode);
1832         }
1834         // Invalid user.
1835         try {
1836             $result = core_message_external::delete_message($m1to2, -1, false);
1837             $this->fail('Exception expected due invalid user.');
1838         } catch (moodle_exception $e) {
1839             $this->assertEquals('invaliduser', $e->errorcode);
1840         }
1842         // Not active user.
1843         delete_user($user2);
1844         try {
1845             $result = core_message_external::delete_message($m1to2, $user2->id, false);
1846             $this->fail('Exception expected due invalid user.');
1847         } catch (moodle_exception $e) {
1848             $this->assertEquals('userdeleted', $e->errorcode);
1849         }
1851         // Now, as an admin, try to delete any message.
1852         $this->setAdminUser();
1853         $result = core_message_external::delete_message($m3to4, $user4->id, false);
1854         $result = external_api::clean_returnvalue(core_message_external::delete_message_returns(), $result);
1855         $this->assertTrue($result['status']);
1856         $this->assertCount(0, $result['warnings']);
1857         $this->assertTrue($DB->record_exists('message_user_actions', array('messageid' => $m3to4, 'userid' => $user4->id,
1858             'action' => \core_message\api::MESSAGE_ACTION_DELETED)));
1860     }
1862     public function test_mark_all_notifications_as_read_invalid_user_exception() {
1863         $this->resetAfterTest(true);
1865         $this->expectException('moodle_exception');
1866         core_message_external::mark_all_notifications_as_read(-2132131, 0);
1867     }
1869     public function test_mark_all_notifications_as_read_access_denied_exception() {
1870         $this->resetAfterTest(true);
1872         $sender = $this->getDataGenerator()->create_user();
1873         $user = $this->getDataGenerator()->create_user();
1875         $this->setUser($user);
1876         $this->expectException('moodle_exception');
1877         core_message_external::mark_all_notifications_as_read($sender->id, 0);
1878     }
1880     public function test_mark_all_notifications_as_read_missing_from_user_exception() {
1881         $this->resetAfterTest(true);
1883         $sender = $this->getDataGenerator()->create_user();
1885         $this->setUser($sender);
1886         $this->expectException('moodle_exception');
1887         core_message_external::mark_all_notifications_as_read($sender->id, 99999);
1888     }
1890     public function test_mark_all_notifications_as_read() {
1891         global $DB;
1893         $this->resetAfterTest(true);
1895         $sender1 = $this->getDataGenerator()->create_user();
1896         $sender2 = $this->getDataGenerator()->create_user();
1897         $sender3 = $this->getDataGenerator()->create_user();
1898         $recipient = $this->getDataGenerator()->create_user();
1900         $this->setUser($recipient);
1902         $this->send_message($sender1, $recipient, 'Notification', 1);
1903         $this->send_message($sender1, $recipient, 'Notification', 1);
1904         $this->send_message($sender2, $recipient, 'Notification', 1);
1905         $this->send_message($sender2, $recipient, 'Notification', 1);
1906         $this->send_message($sender3, $recipient, 'Notification', 1);
1907         $this->send_message($sender3, $recipient, 'Notification', 1);
1909         core_message_external::mark_all_notifications_as_read($recipient->id, $sender1->id);
1910         $readnotifications = $DB->get_records_select('notifications', 'useridto = ? AND timeread IS NOT NULL', [$recipient->id]);
1911         $unreadnotifications = $DB->get_records_select('notifications', 'useridto = ? AND timeread IS NULL', [$recipient->id]);
1913         $this->assertCount(2, $readnotifications);
1914         $this->assertCount(4, $unreadnotifications);
1916         core_message_external::mark_all_notifications_as_read($recipient->id, 0);
1917         $readnotifications = $DB->get_records_select('notifications', 'useridto = ? AND timeread IS NOT NULL', [$recipient->id]);
1918         $unreadnotifications = $DB->get_records_select('notifications', 'useridto = ? AND timeread IS NULL', [$recipient->id]);
1920         $this->assertCount(6, $readnotifications);
1921         $this->assertCount(0, $unreadnotifications);
1922     }
1924     public function test_mark_all_notifications_as_read_time_created_to() {
1925         global $DB;
1927         $this->resetAfterTest(true);
1929         $sender1 = $this->getDataGenerator()->create_user();
1930         $sender2 = $this->getDataGenerator()->create_user();
1932         $recipient = $this->getDataGenerator()->create_user();
1933         $this->setUser($recipient);
1935         // Record messages as sent on one second intervals.
1936         $time = time();
1938         $this->send_message($sender1, $recipient, 'Message 1', 1, $time);
1939         $this->send_message($sender2, $recipient, 'Message 2', 1, $time + 1);
1940         $this->send_message($sender1, $recipient, 'Message 3', 1, $time + 2);
1941         $this->send_message($sender2, $recipient, 'Message 4', 1, $time + 3);
1943         // Mark notifications sent from sender1 up until the second message; should only mark the first notification as read.
1944         core_message_external::mark_all_notifications_as_read($recipient->id, $sender1->id, $time + 1);
1946         $params = [$recipient->id];
1948         $this->assertEquals(1, $DB->count_records_select('notifications', 'useridto = ? AND timeread IS NOT NULL', $params));
1949         $this->assertEquals(3, $DB->count_records_select('notifications', 'useridto = ? AND timeread IS NULL', $params));
1951         // Mark all notifications as read from any sender up to the time the third message was sent.
1952         core_message_external::mark_all_notifications_as_read($recipient->id, 0, $time + 2);
1954         $this->assertEquals(3, $DB->count_records_select('notifications', 'useridto = ? AND timeread IS NOT NULL', $params));
1955         $this->assertEquals(1, $DB->count_records_select('notifications', 'useridto = ? AND timeread IS NULL', $params));
1957         // Mark all notifications as read from any sender with a time after all messages were sent.
1958         core_message_external::mark_all_notifications_as_read($recipient->id, 0, $time + 10);
1960         $this->assertEquals(4, $DB->count_records_select('notifications', 'useridto = ? AND timeread IS NOT NULL', $params));
1961         $this->assertEquals(0, $DB->count_records_select('notifications', 'useridto = ? AND timeread IS NULL', $params));
1962     }
1964     /**
1965      * Test get_user_notification_preferences
1966      */
1967     public function test_get_user_notification_preferences() {
1968         $this->resetAfterTest(true);
1970         $user = self::getDataGenerator()->create_user();
1971         $this->setUser($user);
1973         // Set a couple of preferences to test.
1974         set_user_preference('message_provider_mod_assign_assign_notification_loggedin', 'popup', $user);
1975         set_user_preference('message_provider_mod_assign_assign_notification_loggedoff', 'email', $user);
1977         $prefs = core_message_external::get_user_notification_preferences();
1978         $prefs = external_api::clean_returnvalue(core_message_external::get_user_notification_preferences_returns(), $prefs);
1979         // Check processors.
1980         $this->assertGreaterThanOrEqual(2, count($prefs['preferences']['processors']));
1981         $this->assertEquals($user->id, $prefs['preferences']['userid']);
1983         // Check components.
1984         $this->assertGreaterThanOrEqual(8, count($prefs['preferences']['components']));
1986         // Check some preferences that we previously set.
1987         $found = 0;
1988         foreach ($prefs['preferences']['components'] as $component) {
1989             foreach ($component['notifications'] as $prefdata) {
1990                 if ($prefdata['preferencekey'] != 'message_provider_mod_assign_assign_notification') {
1991                     continue;
1992                 }
1993                 foreach ($prefdata['processors'] as $processor) {
1994                     if ($processor['name'] == 'popup') {
1995                         $this->assertTrue($processor['loggedin']['checked']);
1996                         $found++;
1997                     } else if ($processor['name'] == 'email') {
1998                         $this->assertTrue($processor['loggedoff']['checked']);
1999                         $found++;
2000                     }
2001                 }
2002             }
2003         }
2004         $this->assertEquals(2, $found);
2005     }
2007     /**
2008      * Test get_user_notification_preferences permissions
2009      */
2010     public function test_get_user_notification_preferences_permissions() {
2011         $this->resetAfterTest(true);
2013         $user = self::getDataGenerator()->create_user();
2014         $otheruser = self::getDataGenerator()->create_user();
2015         $this->setUser($user);
2017         $this->expectException('moodle_exception');
2018         $prefs = core_message_external::get_user_notification_preferences($otheruser->id);
2019     }
2021     /**
2022      * Tests searching for users when site-wide messaging is disabled.
2023      *
2024      * This test verifies that any contacts are returned, as well as any non-contacts whose profile we can view.
2025      * If checks this by placing some users in the same course, where default caps would permit a user to view another user's
2026      * profile.
2027      */
2028     public function test_message_search_users_messagingallusers_disabled() {
2029         global $DB;
2030         $this->resetAfterTest();
2032         // Create some users.
2033         $users = [];
2034         foreach (range(1, 8) as $i) {
2035             $user = new stdClass();
2036             $user->firstname = ($i == 4) ? 'User' : 'User search'; // Ensure the fourth user won't match the search term.
2037             $user->lastname = $i;
2038             $user = $this->getDataGenerator()->create_user($user);
2039             $users[$i] = $user;
2040         }
2042         // Enrol a few users in the same course, but leave them as non-contacts.
2043         $course1 = $this->getDataGenerator()->create_course();
2044         $course2 = $this->getDataGenerator()->create_course();
2046         $this->setAdminUser();
2047         $this->getDataGenerator()->enrol_user($users[1]->id, $course1->id);
2048         $this->getDataGenerator()->enrol_user($users[6]->id, $course1->id);
2049         $this->getDataGenerator()->enrol_user($users[7]->id, $course1->id);
2051         // Add some other users as contacts.
2052         \core_message\api::add_contact($users[1]->id, $users[2]->id);
2053         \core_message\api::add_contact($users[3]->id, $users[1]->id);
2054         \core_message\api::add_contact($users[1]->id, $users[4]->id);
2056         // Enrol a user as a teacher in the course, and make the teacher role a course contact role.
2057         $this->getDataGenerator()->enrol_user($users[8]->id, $course2->id, 'editingteacher');
2058         $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
2059         set_config('coursecontact', $teacherrole->id);
2061         // Create individual conversations between some users, one contact and one non-contact.
2062         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
2063             [$users[1]->id, $users[2]->id]);
2064         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
2065             [$users[6]->id, $users[1]->id]);
2067         // Create a group conversation between 4 users, including a contact and a non-contact.
2068         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2069             [$users[1]->id, $users[2]->id, $users[4]->id, $users[7]->id], 'Project chat');
2071         // Set as the user performing the search.
2072         $this->setUser($users[1]);
2074         // Perform a search with $CFG->messagingallusers disabled.
2075         set_config('messagingallusers', 0);
2076         $result = core_message_external::message_search_users($users[1]->id, 'search');
2077         $result = external_api::clean_returnvalue(core_message_external::message_search_users_returns(), $result);
2079         // Confirm that we returns contacts and non-contacts.
2080         $this->assertArrayHasKey('contacts', $result);
2081         $this->assertArrayHasKey('noncontacts', $result);
2082         $contacts = $result['contacts'];
2083         $noncontacts = $result['noncontacts'];
2085         // Check that we retrieved the correct contacts.
2086         $this->assertCount(2, $contacts);
2087         $this->assertEquals($users[2]->id, $contacts[0]['id']);
2088         $this->assertEquals($users[3]->id, $contacts[1]['id']);
2090         // Verify the correct conversations were returned for the contacts.
2091         $this->assertCount(2, $contacts[0]['conversations']);
2092         // We can't rely on the ordering of conversations within the results, so sort by id first.
2093         usort($contacts[0]['conversations'], function($a, $b) {
2094             return $b['id'] <=> $a['id'];
2095         });
2096         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $contacts[0]['conversations'][0]['type']);
2097         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $contacts[0]['conversations'][1]['type']);
2099         $this->assertCount(0, $contacts[1]['conversations']);
2101         // Check that we retrieved the correct non-contacts.
2102         // When site wide messaging is disabled, we expect to see only those users who we share a course with and whose profiles
2103         // are visible in that course. This excludes users like course contacts.
2104         $this->assertCount(3, $noncontacts);
2105         // Self-conversation first.
2106         $this->assertEquals($users[1]->id, $noncontacts[0]['id']);
2107         $this->assertEquals($users[6]->id, $noncontacts[1]['id']);
2108         $this->assertEquals($users[7]->id, $noncontacts[2]['id']);
2110         // Verify the correct conversations were returned for the non-contacts.
2111         $this->assertCount(1, $noncontacts[1]['conversations']);
2112         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $noncontacts[1]['conversations'][0]['type']);
2114         $this->assertCount(1, $noncontacts[2]['conversations']);
2115         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $noncontacts[2]['conversations'][0]['type']);
2116     }
2118     /**
2119      * Tests searching for users when site-wide messaging is enabled.
2120      *
2121      * This test verifies that any contacts are returned, as well as any non-contacts, regardless of whether the searching user
2122      * can view their respective profile.
2123      */
2124     public function test_message_search_users_messagingallusers_enabled() {
2125         global $DB;
2126         $this->resetAfterTest();
2128         // Create some users.
2129         $users = [];
2130         foreach (range(1, 9) as $i) {
2131             $user = new stdClass();
2132             $user->firstname = ($i == 4) ? 'User' : 'User search'; // Ensure the fourth user won't match the search term.
2133             $user->lastname = $i;
2134             $user = $this->getDataGenerator()->create_user($user);
2135             $users[$i] = $user;
2136         }
2138         // Enrol a few users in the same course, but leave them as non-contacts.
2139         $course1 = $this->getDataGenerator()->create_course();
2140         $course2 = $this->getDataGenerator()->create_course();
2142         $this->setAdminUser();
2143         $this->getDataGenerator()->enrol_user($users[1]->id, $course1->id);
2144         $this->getDataGenerator()->enrol_user($users[6]->id, $course1->id);
2145         $this->getDataGenerator()->enrol_user($users[7]->id, $course1->id);
2147         // Add some other users as contacts.
2148         \core_message\api::add_contact($users[1]->id, $users[2]->id);
2149         \core_message\api::add_contact($users[3]->id, $users[1]->id);
2150         \core_message\api::add_contact($users[1]->id, $users[4]->id);
2152         // Enrol a user as a teacher in the course, and make the teacher role a course contact role.
2153         $this->getDataGenerator()->enrol_user($users[9]->id, $course2->id, 'editingteacher');
2154         $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
2155         set_config('coursecontact', $teacherrole->id);
2157         // Create individual conversations between some users, one contact and one non-contact.
2158         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
2159             [$users[1]->id, $users[2]->id]);
2160         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL,
2161             [$users[6]->id, $users[1]->id]);
2163         // Create a group conversation between 5 users, including a contact and a non-contact, and a user NOT in a shared course.
2164         \core_message\api::create_conversation(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2165             [$users[1]->id, $users[2]->id, $users[4]->id, $users[7]->id, $users[8]->id], 'Project chat');
2167         // Set as the user performing the search.
2168         $this->setUser($users[1]);
2170         // Perform a search with $CFG->messagingallusers enabled.
2171         set_config('messagingallusers', 1);
2172         $result = core_message_external::message_search_users($users[1]->id, 'search');
2173         $result = external_api::clean_returnvalue(core_message_external::message_search_users_returns(), $result);
2175         // Confirm that we returns contacts and non-contacts.
2176         $this->assertArrayHasKey('contacts', $result);
2177         $this->assertArrayHasKey('noncontacts', $result);
2178         $contacts = $result['contacts'];
2179         $noncontacts = $result['noncontacts'];
2181         // Check that we retrieved the correct contacts.
2182         $this->assertCount(2, $contacts);
2183         $this->assertEquals($users[2]->id, $contacts[0]['id']);
2184         $this->assertEquals($users[3]->id, $contacts[1]['id']);
2186         // Verify the correct conversations were returned for the contacts.
2187         $this->assertCount(2, $contacts[0]['conversations']);
2188         // We can't rely on the ordering of conversations within the results, so sort by id first.
2189         usort($contacts[0]['conversations'], function($a, $b) {
2190             return $b['id'] <=> $a['id'];
2191         });
2192         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $contacts[0]['conversations'][0]['type']);
2193         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $contacts[0]['conversations'][1]['type']);
2195         $this->assertCount(0, $contacts[1]['conversations']);
2197         // Check that we retrieved the correct non-contacts.
2198         // If site wide messaging is enabled, we expect to be able to search for any users whose profiles we can view.
2199         // In this case, as a student, that's the course contact for course2 and those noncontacts sharing a course with user1.
2200         $this->assertCount(4, $noncontacts);
2201         $this->assertEquals($users[1]->id, $noncontacts[0]['id']);
2202         $this->assertEquals($users[6]->id, $noncontacts[1]['id']);
2203         $this->assertEquals($users[7]->id, $noncontacts[2]['id']);
2204         $this->assertEquals($users[9]->id, $noncontacts[3]['id']);
2206         // Verify the correct conversations were returned for the non-contacts.
2207         $this->assertCount(1, $noncontacts[1]['conversations']);
2208         $this->assertCount(1, $noncontacts[2]['conversations']);
2209         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_INDIVIDUAL, $noncontacts[1]['conversations'][0]['type']);
2210         $this->assertEquals(\core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP, $noncontacts[2]['conversations'][0]['type']);
2211         $this->assertCount(0, $noncontacts[3]['conversations']);
2212     }
2214     /**
2215      * Verify searching for users find themselves when they have self-conversations.
2216      */
2217     public function test_message_search_users_self_conversations() {
2218         $this->resetAfterTest();
2220         // Create some users.
2221         $user1 = new stdClass();
2222         $user1->firstname = 'User';
2223         $user1->lastname = 'One';
2224         $user1 = $this->getDataGenerator()->create_user($user1);
2225         $user2 = new stdClass();
2226         $user2->firstname = 'User';
2227         $user2->lastname = 'Two';
2228         $user2 = $this->getDataGenerator()->create_user($user2);
2230         // Get self-conversation for user1.
2231         $sc1 = \core_message\api::get_self_conversation($user1->id);
2232         testhelper::send_fake_message_to_conversation($user1, $sc1->id, 'Hi myself!');
2234         // Perform a search as user1.
2235         $this->setUser($user1);
2236         $result = core_message_external::message_search_users($user1->id, 'One');
2237         $result = external_api::clean_returnvalue(core_message_external::message_search_users_returns(), $result);
2239         // Check results are empty.
2240         $this->assertCount(0, $result['contacts']);
2241         $this->assertCount(1, $result['noncontacts']);
2242     }
2244     /**
2245      * Verify searching for users works even if no matching users from either contacts, or non-contacts can be found.
2246      */
2247     public function test_message_search_users_with_empty_result() {
2248         $this->resetAfterTest();
2250         // Create some users, but make sure neither will match the search term.
2251         $user1 = new stdClass();
2252         $user1->firstname = 'User';
2253         $user1->lastname = 'One';
2254         $user1 = $this->getDataGenerator()->create_user($user1);
2255         $user2 = new stdClass();
2256         $user2->firstname = 'User';
2257         $user2->lastname = 'Two';
2258         $user2 = $this->getDataGenerator()->create_user($user2);
2260         // Perform a search as user1.
2261         $this->setUser($user1);
2262         $result = core_message_external::message_search_users($user1->id, 'search');
2263         $result = external_api::clean_returnvalue(core_message_external::message_search_users_returns(), $result);
2265         // Check results are empty.
2266         $this->assertCount(0, $result['contacts']);
2267         $this->assertCount(0, $result['noncontacts']);
2268     }
2270     /**
2271      * Test verifying that limits and offsets work for both the contacts and non-contacts return data.
2272      */
2273     public function test_message_search_users_limit_offset() {
2274         $this->resetAfterTest();
2276         // Create 20 users.
2277         $users = [];
2278         foreach (range(1, 20) as $i) {
2279             $user = new stdClass();
2280             $user->firstname = "User search";
2281             $user->lastname = $i;
2282             $user = $this->getDataGenerator()->create_user($user);
2283             $users[$i] = $user;
2284         }
2286         // Enrol the first 8 users in the same course, but leave them as non-contacts.
2287         $this->setAdminUser();
2288         $course1 = $this->getDataGenerator()->create_course();
2289         foreach (range(1, 8) as $i) {
2290             $this->getDataGenerator()->enrol_user($users[$i]->id, $course1->id);
2291         }
2293         // Add 5 users, starting at the 11th user, as contacts for user1.
2294         foreach (range(11, 15) as $i) {
2295             \core_message\api::add_contact($users[1]->id, $users[$i]->id);
2296         }
2298         // Set as the user performing the search.
2299         $this->setUser($users[1]);
2301         // Search using a limit of 3.
2302         // This tests the case where we have more results than the limit for both contacts and non-contacts.
2303         $result = core_message_external::message_search_users($users[1]->id, 'search', 0, 3);
2304         $result = external_api::clean_returnvalue(core_message_external::message_search_users_returns(), $result);
2305         $contacts = $result['contacts'];
2306         $noncontacts = $result['noncontacts'];
2308         // Check that we retrieved the correct contacts.
2309         $this->assertCount(3, $contacts);
2310         $this->assertEquals($users[11]->id, $contacts[0]['id']);
2311         $this->assertEquals($users[12]->id, $contacts[1]['id']);
2312         $this->assertEquals($users[13]->id, $contacts[2]['id']);
2314         // Check that we retrieved the correct non-contacts.
2315         // Consider first conversation is self-conversation.
2316         $this->assertCount(3, $noncontacts);
2317         $this->assertEquals($users[1]->id, $noncontacts[0]['id']);
2318         $this->assertEquals($users[2]->id, $noncontacts[1]['id']);
2319         $this->assertEquals($users[3]->id, $noncontacts[2]['id']);
2321         // Now, offset to get the next batch of results.
2322         // We expect to see 2 contacts, and 3 non-contacts.
2323         $result = core_message_external::message_search_users($users[1]->id, 'search', 3, 3);
2324         $result = external_api::clean_returnvalue(core_message_external::message_search_users_returns(), $result);
2325         $contacts = $result['contacts'];
2326         $noncontacts = $result['noncontacts'];
2327         $this->assertCount(2, $contacts);
2328         $this->assertEquals($users[14]->id, $contacts[0]['id']);
2329         $this->assertEquals($users[15]->id, $contacts[1]['id']);
2331         $this->assertCount(3, $noncontacts);
2332         $this->assertEquals($users[4]->id, $noncontacts[0]['id']);
2333         $this->assertEquals($users[5]->id, $noncontacts[1]['id']);
2334         $this->assertEquals($users[6]->id, $noncontacts[2]['id']);
2336         // Now, offset to get the next batch of results.
2337         // We expect to see 0 contacts, and 2 non-contacts.
2338         $result = core_message_external::message_search_users($users[1]->id, 'search', 6, 3);
2339         $result = external_api::clean_returnvalue(core_message_external::message_search_users_returns(), $result);
2340         $contacts = $result['contacts'];
2341         $noncontacts = $result['noncontacts'];
2342         $this->assertCount(0, $contacts);
2344         $this->assertCount(2, $noncontacts);
2345         $this->assertEquals($users[7]->id, $noncontacts[0]['id']);
2346         $this->assertEquals($users[8]->id, $noncontacts[1]['id']);
2347     }
2349     /**
2350      * Tests searching users as another user having the 'moodle/user:viewdetails' capability.
2351      */
2352     public function test_message_search_users_with_cap() {
2353         $this->resetAfterTest();
2354         global $DB;
2356         // Create some users.
2357         $users = [];
2358         foreach (range(1, 8) as $i) {
2359             $user = new stdClass();
2360             $user->firstname = ($i == 4) ? 'User' : 'User search'; // Ensure the fourth user won't match the search term.
2361             $user->lastname = $i;
2362             $user = $this->getDataGenerator()->create_user($user);
2363             $users[$i] = $user;
2364         }
2366         // Enrol a few users in the same course, but leave them as non-contacts.
2367         $course1 = $this->getDataGenerator()->create_course();
2368         $this->setAdminUser();
2369         $this->getDataGenerator()->enrol_user($users[1]->id, $course1->id);
2370         $this->getDataGenerator()->enrol_user($users[6]->id, $course1->id);
2371         $this->getDataGenerator()->enrol_user($users[7]->id, $course1->id);
2373         // Add some other users as contacts.
2374         \core_message\api::add_contact($users[1]->id, $users[2]->id);
2375         \core_message\api::add_contact($users[3]->id, $users[1]->id);
2376         \core_message\api::add_contact($users[1]->id, $users[4]->id);
2378         // Set as the user performing the search.
2379         $this->setUser($users[1]);
2381         // Grant the authenticated user role the capability 'user:viewdetails' at site context.
2382         $authenticatedrole = $DB->get_record('role', ['shortname' => 'user'], '*', MUST_EXIST);
2383         assign_capability('moodle/user:viewdetails', CAP_ALLOW, $authenticatedrole->id, context_system::instance());
2385         // Perform a search with $CFG->messagingallusers disabled.
2386         set_config('messagingallusers', 0);
2387         $result = core_message_external::message_search_users($users[1]->id, 'search');
2388         $result = external_api::clean_returnvalue(core_message_external::message_search_users_returns(), $result);
2389         $contacts = $result['contacts'];
2390         $noncontacts = $result['noncontacts'];
2392         // Check that we retrieved the correct contacts.
2393         $this->assertCount(2, $contacts);
2394         $this->assertEquals($users[2]->id, $contacts[0]['id']);
2395         $this->assertEquals($users[3]->id, $contacts[1]['id']);
2397         // Check that we retrieved the correct non-contacts.
2398         // Site-wide messaging is disabled, so we expect to be able to search for any users whose profile we can view.
2399         // Consider first conversations is self-conversation.
2400         $this->assertCount(3, $noncontacts);
2401         $this->assertEquals($users[1]->id, $noncontacts[0]['id']);
2402         $this->assertEquals($users[6]->id, $noncontacts[1]['id']);
2403         $this->assertEquals($users[7]->id, $noncontacts[2]['id']);
2404     }
2406     /**
2407      * Tests searching users as another user without the 'moodle/user:viewdetails' capability.
2408      */
2409     public function test_message_search_users_without_cap() {
2410         $this->resetAfterTest();
2412         // Create some users.
2413         $user1 = $this->getDataGenerator()->create_user();
2414         $user2 = $this->getDataGenerator()->create_user();
2416         // The person doing the search for another user.
2417         $this->setUser($user1);
2419         // Ensure an exception is thrown.
2420         $this->expectException('moodle_exception');
2421         core_message_external::message_search_users($user2->id, 'User');
2422         $this->assertDebuggingCalled();
2423     }
2425     /**
2426      * Tests searching users with messaging disabled.
2427      */
2428     public function test_message_search_users_messaging_disabled() {
2429         $this->resetAfterTest();
2431         // Create some skeleton data just so we can call the WS.
2432         $user = $this->getDataGenerator()->create_user();
2434         // The person doing the search.
2435         $this->setUser($user);
2437         // Disable messaging.
2438         set_config('messaging', 0);
2440         // Ensure an exception is thrown.
2441         $this->expectException('moodle_exception');
2442         core_message_external::message_search_users($user->id, 'User');
2443     }
2445     /**
2446      * Tests searching messages.
2447      */
2448     public function test_messagearea_search_messages() {
2449         $this->resetAfterTest(true);
2451         // Create some users.
2452         $user1 = self::getDataGenerator()->create_user();
2453         $user2 = self::getDataGenerator()->create_user();
2455         // The person doing the search.
2456         $this->setUser($user1);
2458         // Send some messages back and forth.
2459         $time = time();
2460         $this->send_message($user1, $user2, 'Yo!', 0, $time);
2461         $this->send_message($user2, $user1, 'Sup mang?', 0, $time + 1);
2462         $this->send_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 2);
2463         $this->send_message($user2, $user1, 'Word.', 0, $time + 3);
2464         $convid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
2466         // Perform a search.
2467         $result = core_message_external::data_for_messagearea_search_messages($user1->id, 'o');
2469         // We need to execute the return values cleaning process to simulate the web service server.
2470         $result = external_api::clean_returnvalue(core_message_external::data_for_messagearea_search_messages_returns(), $result);
2472         // Confirm the data is correct.
2473         $messages = $result['contacts'];
2474         $this->assertCount(2, $messages);
2476         $message1 = $messages[0];
2477         $message2 = $messages[1];
2479         $this->assertEquals($user2->id, $message1['userid']);
2480         $this->assertEquals(fullname($user2), $message1['fullname']);
2481         $this->assertTrue($message1['ismessaging']);
2482         $this->assertFalse($message1['sentfromcurrentuser']);
2483         $this->assertEquals('Word.', $message1['lastmessage']);
2484         $this->assertNotEmpty($message1['messageid']);
2485         $this->assertNull($message1['isonline']);
2486         $this->assertFalse($message1['isread']);
2487         $this->assertFalse($message1['isblocked']);
2488         $this->assertNull($message1['unreadcount']);
2489         $this->assertEquals($convid, $message1['conversationid']);
2491         $this->assertEquals($user2->id, $message2['userid']);
2492         $this->assertEquals(fullname($user2), $message2['fullname']);
2493         $this->assertTrue($message2['ismessaging']);
2494         $this->assertTrue($message2['sentfromcurrentuser']);
2495         $this->assertEquals('Yo!', $message2['lastmessage']);
2496         $this->assertNotEmpty($message2['messageid']);
2497         $this->assertNull($message2['isonline']);
2498         $this->assertTrue($message2['isread']);
2499         $this->assertFalse($message2['isblocked']);
2500         $this->assertNull($message2['unreadcount']);
2501         $this->assertEquals($convid, $message2['conversationid']);
2502     }
2504     /**
2505      * Tests searching messages as another user.
2506      */
2507     public function test_messagearea_search_messages_as_other_user() {
2508         $this->resetAfterTest(true);
2510         // The person doing the search.
2511         $this->setAdminUser();
2513         // Create some users.
2514         $user1 = self::getDataGenerator()->create_user();
2515         $user2 = self::getDataGenerator()->create_user();
2517         // Send some messages back and forth.
2518         $time = time();
2519         $this->send_message($user1, $user2, 'Yo!', 0, $time);
2520         $this->send_message($user2, $user1, 'Sup mang?', 0, $time + 1);
2521         $this->send_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 2);
2522         $this->send_message($user2, $user1, 'Word.', 0, $time + 3);
2524         // Perform a search.
2525         $result = core_message_external::data_for_messagearea_search_messages($user1->id, 'o');
2527         // We need to execute the return values cleaning process to simulate the web service server.
2528         $result = external_api::clean_returnvalue(core_message_external::data_for_messagearea_search_messages_returns(),
2529             $result);
2531         // Confirm the data is correct.
2532         $messages = $result['contacts'];
2533         $this->assertCount(2, $messages);
2535         $message1 = $messages[0];
2536         $message2 = $messages[1];
2538         $this->assertEquals($user2->id, $message1['userid']);
2539         $this->assertEquals(fullname($user2), $message1['fullname']);
2540         $this->assertTrue($message1['ismessaging']);
2541         $this->assertFalse($message1['sentfromcurrentuser']);
2542         $this->assertEquals('Word.', $message1['lastmessage']);
2543         $this->assertNotEmpty($message1['messageid']);
2544         $this->assertFalse($message1['isonline']);
2545         $this->assertFalse($message1['isread']);
2546         $this->assertFalse($message1['isblocked']);
2547         $this->assertNull($message1['unreadcount']);
2549         $this->assertEquals($user2->id, $message2['userid']);
2550         $this->assertEquals(fullname($user2), $message2['fullname']);
2551         $this->assertTrue($message2['ismessaging']);
2552         $this->assertTrue($message2['sentfromcurrentuser']);
2553         $this->assertEquals('Yo!', $message2['lastmessage']);
2554         $this->assertNotEmpty($message2['messageid']);
2555         $this->assertFalse($message2['isonline']);
2556         $this->assertTrue($message2['isread']);
2557         $this->assertFalse($message2['isblocked']);
2558         $this->assertNull($message2['unreadcount']);
2559     }
2561     /**
2562      * Tests searching messages as another user without the proper capabilities.
2563      */
2564     public function test_messagearea_search_messages_as_other_user_without_cap() {
2565         $this->resetAfterTest(true);
2567         // Create some users.
2568         $user1 = self::getDataGenerator()->create_user();
2569         $user2 = self::getDataGenerator()->create_user();
2571         // The person doing the search for another user.
2572         $this->setUser($user1);
2574         // Ensure an exception is thrown.
2575         $this->expectException('moodle_exception');
2576         core_message_external::data_for_messagearea_search_messages($user2->id, 'Search');
2577     }
2579     /**
2580      * Tests searching messages with messaging disabled
2581      */
2582     public function test_messagearea_search_messages_messaging_disabled() {
2583         global $CFG;
2585         $this->resetAfterTest(true);
2587         // Create some skeleton data just so we can call the WS.
2588         $user = self::getDataGenerator()->create_user();
2590         // The person doing the search .
2591         $this->setUser($user);
2593         // Disable messaging.
2594         $CFG->messaging = 0;
2596         // Ensure an exception is thrown.
2597         $this->expectException('moodle_exception');
2598         core_message_external::data_for_messagearea_search_messages($user->id, 'Search');
2599     }
2601     /**
2602      * Tests retrieving contacts.
2603      */
2604     public function test_get_user_contacts() {
2605         $this->resetAfterTest(true);
2607         // Create some users.
2608         $user1 = self::getDataGenerator()->create_user();
2610         // Set as the user.
2611         $this->setUser($user1);
2613         $user2 = new stdClass();
2614         $user2->firstname = 'User';
2615         $user2->lastname = 'A';
2616         $user2 = self::getDataGenerator()->create_user($user2);
2618         $user3 = new stdClass();
2619         $user3->firstname = 'User';
2620         $user3->lastname = 'B';
2621         $user3 = self::getDataGenerator()->create_user($user3);
2623         $user4 = new stdClass();
2624         $user4->firstname = 'User';
2625         $user4->lastname = 'C';
2626         $user4 = self::getDataGenerator()->create_user($user4);
2628         $user5 = new stdClass();
2629         $user5->firstname = 'User';
2630         $user5->lastname = 'D';
2631         $user5 = self::getDataGenerator()->create_user($user5);
2633         // Add some users as contacts.
2634         \core_message\api::add_contact($user1->id, $user2->id);
2635         \core_message\api::add_contact($user1->id, $user3->id);
2636         \core_message\api::add_contact($user1->id, $user4->id);
2638         // Retrieve the contacts.
2639         $result = core_message_external::get_user_contacts($user1->id);
2641         // We need to execute the return values cleaning process to simulate the web service server.
2642         $result = external_api::clean_returnvalue(core_message_external::get_user_contacts_returns(),
2643             $result);
2645         // Confirm the data is correct.
2646         $contacts = $result;
2647         usort($contacts, ['static', 'sort_contacts_id']);
2648         $this->assertCount(3, $contacts);
2650         $contact1 = array_shift($contacts);
2651         $contact2 = array_shift($contacts);
2652         $contact3 = array_shift($contacts);
2654         $this->assertEquals($user2->id, $contact1['id']);
2655         $this->assertEquals(fullname($user2), $contact1['fullname']);
2656         $this->assertTrue($contact1['iscontact']);
2658         $this->assertEquals($user3->id, $contact2['id']);
2659         $this->assertEquals(fullname($user3), $contact2['fullname']);
2660         $this->assertTrue($contact2['iscontact']);
2662         $this->assertEquals($user4->id, $contact3['id']);
2663         $this->assertEquals(fullname($user4), $contact3['fullname']);
2664         $this->assertTrue($contact3['iscontact']);
2665     }
2667     /**
2668      * Tests retrieving contacts as another user.
2669      */
2670     public function test_get_user_contacts_as_other_user() {
2671         $this->resetAfterTest(true);
2673         $this->setAdminUser();
2675         // Create some users.
2676         $user1 = self::getDataGenerator()->create_user();
2678         $user2 = new stdClass();
2679         $user2->firstname = 'User';
2680         $user2->lastname = 'A';
2681         $user2 = self::getDataGenerator()->create_user($user2);
2683         $user3 = new stdClass();
2684         $user3->firstname = 'User';
2685         $user3->lastname = 'B';
2686         $user3 = self::getDataGenerator()->create_user($user3);
2688         $user4 = new stdClass();
2689         $user4->firstname = 'User';
2690         $user4->lastname = 'C';
2691         $user4 = self::getDataGenerator()->create_user($user4);
2693         $user5 = new stdClass();
2694         $user5->firstname = 'User';
2695         $user5->lastname = 'D';
2696         $user5 = self::getDataGenerator()->create_user($user5);
2698         // Add some users as contacts.
2699         \core_message\api::add_contact($user1->id, $user2->id);
2700         \core_message\api::add_contact($user1->id, $user3->id);
2701         \core_message\api::add_contact($user1->id, $user4->id);
2703         // Retrieve the contacts.
2704         $result = core_message_external::get_user_contacts($user1->id);
2706         // We need to execute the return values cleaning process to simulate the web service server.
2707         $result = external_api::clean_returnvalue(core_message_external::get_user_contacts_returns(),
2708             $result);
2710         // Confirm the data is correct.
2711         $contacts = $result;
2712         usort($contacts, ['static', 'sort_contacts_id']);
2713         $this->assertCount(3, $contacts);
2715         $contact1 = array_shift($contacts);
2716         $contact2 = array_shift($contacts);
2717         $contact3 = array_shift($contacts);
2719         $this->assertEquals($user2->id, $contact1['id']);
2720         $this->assertEquals(fullname($user2), $contact1['fullname']);
2721         $this->assertTrue($contact1['iscontact']);
2723         $this->assertEquals($user3->id, $contact2['id']);
2724         $this->assertEquals(fullname($user3), $contact2['fullname']);
2725         $this->assertTrue($contact2['iscontact']);
2727         $this->assertEquals($user4->id, $contact3['id']);
2728         $this->assertEquals(fullname($user4), $contact3['fullname']);
2729         $this->assertTrue($contact3['iscontact']);
2730     }
2732     /**
2733      * Tests retrieving contacts as another user without the proper capabilities.
2734      */
2735     public function test_get_user_contacts_as_other_user_without_cap() {
2736         $this->resetAfterTest(true);
2738         // Create some users.
2739         $user1 = self::getDataGenerator()->create_user();
2740         $user2 = self::getDataGenerator()->create_user();
2742         // The person retrieving the contacts for another user.
2743         $this->setUser($user1);
2745         // Perform the WS call and ensure an exception is thrown.
2746         $this->expectException('moodle_exception');
2747         core_message_external::get_user_contacts($user2->id);
2748     }
2750     /**
2751      * Tests retrieving contacts with messaging disabled.
2752      */
2753     public function test_get_user_contacts_messaging_disabled() {
2754         global $CFG;
2756         $this->resetAfterTest(true);
2758         // Create some skeleton data just so we can call the WS.
2759         $user = self::getDataGenerator()->create_user();
2761         // The person retrieving the contacts.
2762         $this->setUser($user);
2764         // Disable messaging.
2765         $CFG->messaging = 0;
2767         // Perform the WS call and ensure we are shown that it is disabled.
2768         $this->expectException('moodle_exception');
2769         core_message_external::get_user_contacts($user->id);
2770     }
2772     /**
2773      * Test getting contacts when there are no results.
2774      */
2775     public function test_get_user_contacts_no_results() {
2776         $this->resetAfterTest();
2778         $user1 = self::getDataGenerator()->create_user();
2780         $this->setUser($user1);
2782         $requests = core_message_external::get_user_contacts($user1->id);
2783         $requests = external_api::clean_returnvalue(core_message_external::get_user_contacts_returns(), $requests);
2785         $this->assertEmpty($requests);
2786     }
2788     /**
2789      * Tests get_conversation_messages for retrieving messages.
2790      */
2791     public function test_get_conversation_messages() {
2792         $this->resetAfterTest(true);
2794         // Create some users.
2795         $user1 = self::getDataGenerator()->create_user();
2796         $user2 = self::getDataGenerator()->create_user();
2797         $user3 = self::getDataGenerator()->create_user();
2798         $user4 = self::getDataGenerator()->create_user();
2799         $user5 = self::getDataGenerator()->create_user();
2801         // Create group conversation.
2802         $conversation = \core_message\api::create_conversation(
2803             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2804             [$user1->id, $user2->id, $user3->id, $user4->id]
2805         );
2807         // The person asking for the messages.
2808         $this->setUser($user1);
2810         // Send some messages back and forth.
2811         $time = time();
2812         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time);
2813         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Sup mang?', $time + 1);
2814         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Writing PHPUnit tests!', $time + 2);
2815         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Word.', $time + 3);
2817         // Retrieve the messages.
2818         $result = core_message_external::get_conversation_messages($user1->id, $conversation->id);
2820         // We need to execute the return values cleaning process to simulate the web service server.
2821         $result = external_api::clean_returnvalue(core_message_external::get_conversation_messages_returns(),
2822             $result);
2824         // Check the results are correct.
2825         $this->assertEquals($conversation->id, $result['id']);
2827         // Confirm the members data is correct.
2828         $members = $result['members'];
2829         $this->assertCount(3, $members);
2830         $membersid = [$members[0]['id'], $members[1]['id'], $members[2]['id']];
2831         $this->assertContainsEquals($user1->id, $membersid);
2832         $this->assertContainsEquals($user2->id, $membersid);
2833         $this->assertContainsEquals($user3->id, $membersid);
2835         $membersfullnames = [$members[0]['fullname'], $members[1]['fullname'], $members[2]['fullname']];
2836         $this->assertContainsEquals(fullname($user1), $membersfullnames);
2837         $this->assertContainsEquals(fullname($user2), $membersfullnames);
2838         $this->assertContainsEquals(fullname($user3), $membersfullnames);
2840         // Confirm the messages data is correct.
2841         $messages = $result['messages'];
2842         $this->assertCount(4, $messages);
2844         $message1 = $messages[0];
2845         $message2 = $messages[1];
2846         $message3 = $messages[2];
2847         $message4 = $messages[3];
2849         $this->assertEquals($user1->id, $message1['useridfrom']);
2850         $this->assertStringContainsString('Yo!', $message1['text']);
2852         $this->assertEquals($user3->id, $message2['useridfrom']);
2853         $this->assertStringContainsString('Sup mang?', $message2['text']);
2855         $this->assertEquals($user2->id, $message3['useridfrom']);
2856         $this->assertStringContainsString('Writing PHPUnit tests!', $message3['text']);
2858         $this->assertEquals($user1->id, $message4['useridfrom']);
2859         $this->assertStringContainsString('Word.', $message4['text']);
2860     }
2862     /**
2863      * Tests get_conversation_messages for retrieving messages using timefrom parameter.
2864      */
2865     public function test_get_conversation_messages_timefrom() {
2866         $this->resetAfterTest(true);
2868         // Create some users.
2869         $user1 = self::getDataGenerator()->create_user();
2870         $user2 = self::getDataGenerator()->create_user();
2871         $user3 = self::getDataGenerator()->create_user();
2872         $user4 = self::getDataGenerator()->create_user();
2874         // Create group conversation.
2875         $conversation = \core_message\api::create_conversation(
2876             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2877             [$user1->id, $user2->id, $user3->id]
2878         );
2880         // The person asking for the messages.
2881         $this->setUser($user1);
2883         // Send some messages back and forth.
2884         $time = time();
2885         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Message 1', $time - 4);
2886         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 2', $time - 3);
2887         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 3', $time - 2);
2888         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Message 4', $time - 1);
2890         // Retrieve the messages from $time - 3, which should be the 3 most recent messages.
2891         $result = core_message_external::get_conversation_messages($user1->id, $conversation->id, 0, 0, false, $time - 3);
2893         // We need to execute the return values cleaning process to simulate the web service server.
2894         $result = external_api::clean_returnvalue(core_message_external::get_conversation_messages_returns(),
2895             $result);
2897         // Check the results are correct.
2898         $this->assertEquals($conversation->id, $result['id']);
2900         // Confirm the messages data is correct.
2901         $messages = $result['messages'];
2902         $this->assertCount(3, $messages);
2904         $message1 = $messages[0];
2905         $message2 = $messages[1];
2906         $message3 = $messages[2];
2908         $this->assertStringContainsString('Message 2', $message1['text']);
2909         $this->assertStringContainsString('Message 3', $message2['text']);
2910         $this->assertStringContainsString('Message 4', $message3['text']);
2912         // Confirm the members data is correct.
2913         $members = $result['members'];
2914         $this->assertCount(1, $members);
2915         $this->assertEquals($user2->id, $members[0]['id']);
2916     }
2918     /**
2919      * Tests get_conversation_messages for retrieving messages as another user.
2920      */
2921     public function test_get_conversation_messages_as_other_user() {
2922         $this->resetAfterTest(true);
2924         // Set as admin.
2925         $this->setAdminUser();
2927         // Create some users.
2928         $user1 = self::getDataGenerator()->create_user();
2929         $user2 = self::getDataGenerator()->create_user();
2930         $user3 = self::getDataGenerator()->create_user();
2931         $user4 = self::getDataGenerator()->create_user();
2933         // Create group conversation.
2934         $conversation = \core_message\api::create_conversation(
2935             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
2936             [$user1->id, $user2->id, $user3->id, $user4->id]
2937         );
2939         // Send some messages back and forth.
2940         $time = time();
2941         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Yo!', $time);
2942         testhelper::send_fake_message_to_conversation($user3, $conversation->id, 'Sup mang?', $time + 1);
2943         testhelper::send_fake_message_to_conversation($user2, $conversation->id, 'Writing PHPUnit tests!', $time + 2);
2944         testhelper::send_fake_message_to_conversation($user1, $conversation->id, 'Word.', $time + 3);
2946         // Retrieve the messages.
2947         $result = core_message_external::get_conversation_messages($user1->id, $conversation->id);
2949         // We need to execute the return values cleaning process to simulate the web service server.
2950         $result = external_api::clean_returnvalue(core_message_external::get_conversation_messages_returns(),
2951             $result);
2953         // Check the results are correct.
2954         $this->assertEquals($conversation->id, $result['id']);
2956         // Confirm the members data is correct.
2957         $members = $result['members'];
2958         $this->assertCount(3, $members);
2959         $membersid = [$members[0]['id'], $members[1]['id'], $members[2]['id']];
2960         $this->assertContainsEquals($user1->id, $membersid);
2961         $this->assertContainsEquals($user2->id, $membersid);
2962         $this->assertContainsEquals($user3->id, $membersid);
2964         // Confirm the message data is correct.
2965         $messages = $result['messages'];
2966         $this->assertCount(4, $messages);
2968         $message1 = $messages[0];
2969         $message2 = $messages[1];
2970         $message3 = $messages[2];
2971         $message4 = $messages[3];
2973         $this->assertEquals($user1->id, $message1['useridfrom']);
2974         $this->assertStringContainsString('Yo!', $message1['text']);
2976         $this->assertEquals($user3->id, $message2['useridfrom']);
2977         $this->assertStringContainsString('Sup mang?', $message2['text']);
2979         $this->assertEquals($user2->id, $message3['useridfrom']);
2980         $this->assertStringContainsString('Writing PHPUnit tests!', $message3['text']);
2982         $this->assertEquals($user1->id, $message4['useridfrom']);
2983         $this->assertStringContainsString('Word.', $message4['text']);
2984     }
2986     /**
2987      * Tests get_conversation_messages for retrieving messages as another user without the proper capabilities.
2988      */
2989     public function test_get_conversation_messages_as_other_user_without_cap() {
2990         $this->resetAfterTest(true);
2992         // Create some users.
2993         $user1 = self::getDataGenerator()->create_user();
2994         $user2 = self::getDataGenerator()->create_user();
2995         $user3 = self::getDataGenerator()->create_user();
2996         $user4 = self::getDataGenerator()->create_user();
2998         // Create group conversation.
2999         $conversation = \core_message\api::create_conversation(
3000             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3001             [$user1->id, $user2->id, $user3->id, $user4->id]
3002         );
3004         // The person asking for the messages for another user.
3005         $this->setUser($user1);
3007         // Ensure an exception is thrown.
3008         $this->expectException('moodle_exception');
3009         core_message_external::get_conversation_messages($user2->id, $conversation->id);
3010     }
3012     /**
3013      * Tests get_conversation_messages for retrieving messages as another user not in the conversation.
3014      */
3015     public function test_get_conversation_messages_as_user_not_in_conversation() {
3016         $this->resetAfterTest(true);
3018         // Create some users.
3019         $user1 = self::getDataGenerator()->create_user();
3020         $user2 = self::getDataGenerator()->create_user();
3021         $user3 = self::getDataGenerator()->create_user(); // Not in group.
3023         // Create group conversation.
3024         $conversation = \core_message\api::create_conversation(
3025             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3026             [$user1->id, $user2->id]
3027         );
3029         // The person asking for the messages for a conversation he does not belong to.
3030         $this->setUser($user3);
3032         // Ensure an exception is thrown.
3033         $this->expectExceptionMessage('User is not part of conversation.');
3034         core_message_external::get_conversation_messages($user3->id, $conversation->id);
3035     }
3037     /**
3038      * Tests get_conversation_messages for retrieving messages with messaging disabled.
3039      */
3040     public function test_get_conversation_messages_messaging_disabled() {
3041         $this->resetAfterTest(true);
3043         // Create some skeleton data just so we can call the WS.
3044         $user1 = self::getDataGenerator()->create_user();
3045         $user2 = self::getDataGenerator()->create_user();
3046         $user3 = self::getDataGenerator()->create_user();
3047         $user4 = self::getDataGenerator()->create_user();
3049         // Create group conversation.
3050         $conversation = \core_message\api::create_conversation(
3051             \core_message\api::MESSAGE_CONVERSATION_TYPE_GROUP,
3052             [$user1->id, $user2->id, $user3->id, $user4->id]
3053         );
3055         // The person asking for the messages for another user.
3056         $this->setUser($user1);
3058         // Disable messaging.
3059         set_config('messaging', 0);
3061         // Ensure an exception is thrown.
3062         $this->expectException('moodle_exception');
3063         core_message_external::get_conversation_messages($user1->id, $conversation->id);
3064     }
3066     /**
3067      * Test marking all conversation messages as read with an invalid user.
3068      */
3069     public function test_mark_all_conversation_messages_as_read_invalid_user_exception() {
3070         $this->resetAfterTest(true);
3072         $user1 = self::getDataGenerator()->create_user();
3073         $user2 = self::getDataGenerator()->create_user();
3075         // Send some messages back and forth.
3076         $time = time();
3077         $this->send_message($user1, $user2, 'Yo!', 0, $time);
3078         $this->send_message($user2, $user1, 'Sup mang?', 0, $time + 1);
3079         $this->send_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 2);
3080         $this->send_message($user2, $user1, 'Word.', 0, $time + 3);
3082         $conversationid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
3084         $this->expectException('moodle_exception');
3085         core_message_external::mark_all_conversation_messages_as_read(-2132131, $conversationid);
3086     }
3088     /**
3089      * Test marking all conversation messages as read without proper access.
3090      */
3091     public function test_mark_all_conversation_messages_as_read_access_denied_exception() {
3092         $this->resetAfterTest(true);
3094         $user1 = self::getDataGenerator()->create_user();
3095         $user2 = self::getDataGenerator()->create_user();
3096         $user3 = self::getDataGenerator()->create_user();
3098         // Send some messages back and forth.
3099         $time = time();
3100         $this->send_message($user1, $user2, 'Yo!', 0, $time);
3101         $this->send_message($user2, $user1, 'Sup mang?', 0, $time + 1);
3102         $this->send_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 2);
3103         $this->send_message($user2, $user1, 'Word.', 0, $time + 3);
3105         $conversationid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
3107         // User 3 is not in the conversation.
3108         $this->expectException('moodle_exception');
3109         core_message_external::mark_all_conversation_messages_as_read($user3->id, $conversationid);
3110     }
3112     /**
3113      * Test marking all conversation messages as read for another user.
3114      */
3115     public function test_mark_all_conversation_messages_as_read_wrong_user() {
3116         $this->resetAfterTest(true);
3118         $user1 = self::getDataGenerator()->create_user();
3119         $user2 = self::getDataGenerator()->create_user();
3121         // Send some messages back and forth.
3122         $time = time();
3123         $this->send_message($user1, $user2, 'Yo!', 0, $time);
3124         $this->send_message($user2, $user1, 'Sup mang?', 0, $time + 1);
3125         $this->send_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 2);
3126         $this->send_message($user2, $user1, 'Word.', 0, $time + 3);
3128         $conversationid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
3130         // Can't mark the messages as read for user 2.
3131         $this->setUser($user1);
3132         $this->expectException('moodle_exception');
3133         core_message_external::mark_all_conversation_messages_as_read($user2->id, $conversationid);
3134     }
3136     /**
3137      * Test marking all conversation messages as admin.
3138      */
3139     public function test_mark_all_conversation_messages_as_admin() {
3140         global $DB;
3142         $this->resetAfterTest(true);
3144         $user1 = self::getDataGenerator()->create_user();
3145         $user2 = self::getDataGenerator()->create_user();
3147         // Send some messages back and forth.
3148         $time = time();
3149         $this->send_message($user1, $user2, 'Yo!', 0, $time);
3150         $this->send_message($user2, $user1, 'Sup mang?', 0, $time + 1);
3151         $this->send_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 2);
3152         $this->send_message($user2, $user1, 'Word.', 0, $time + 3);
3154         $conversationid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
3156         // Admin can do anything.
3157         $this->setAdminUser();
3158         core_message_external::mark_all_conversation_messages_as_read($user2->id, $conversationid);
3159         $this->assertEquals(2, $DB->count_records('message_user_actions'));
3160     }
3162     /**
3163      * Test marking all conversation messages.
3164      */
3165     public function test_mark_all_conversation_messages_as_read() {
3166         global $DB;
3168         $this->resetAfterTest(true);
3170         $user1 = self::getDataGenerator()->create_user();
3171         $user2 = self::getDataGenerator()->create_user();
3173         // Send some messages back and forth.
3174         $time = time();
3175         $this->send_message($user1, $user2, 'Yo!', 0, $time);
3176         $this->send_message($user2, $user1, 'Sup mang?', 0, $time + 1);
3177         $this->send_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 2);
3178         $this->send_message($user2, $user1, 'Word.', 0, $time + 3);
3180         $conversationid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
3182         // We are the user we want to mark the messages for and we are in the conversation, all good.
3183         $this->setUser($user1);
3184         core_message_external::mark_all_conversation_messages_as_read($user1->id, $conversationid);
3185         $this->assertEquals(2, $DB->count_records('message_user_actions'));
3186     }
3188     /**
3189      * Test getting unread conversation count.
3190      */
3191     public function test_get_unread_conversations_count() {
3192         $this->resetAfterTest(true);
3194         // Create some users.
3195         $user1 = self::getDataGenerator()->create_user();
3196         $user2 = self::getDataGenerator()->create_user();
3197         $user3 = self::getDataGenerator()->create_user();
3198         $user4 = self::getDataGenerator()->create_user();
3200         // The person wanting the conversation count.
3201         $this->setUser($user1);
3203         // Send some messages back and forth, have some different conversations with different users.
3204         $this->send_message($user1, $user2, 'Yo!');
3205         $this->send_message($user2, $user1, 'Sup mang?');
3206         $this->send_message($user1, $user2, 'Writing PHPUnit tests!');
3207         $this->send_message($user2, $user1, 'Word.');
3209         $this->send_message($user1, $user3, 'Booyah');
3210         $this->send_message($user3, $user1, 'Whaaat?');
3211         $this->send_message($user1, $user3, 'Nothing.');
3212         $this->send_message($user3, $user1, 'Cool.');
3214         $this->send_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?');
3215         $this->send_message($user4, $user1, 'Yah brah, it\'s pretty rad.');
3216         $this->send_message($user1, $user4, 'Dope.');
3218         // Get the unread conversation count.
3219         $result = core_message_external::get_unread_conversations_count($user1->id);
3221         // We need to execute the return values cleaning process to simulate the web service server.
3222         $result = external_api::clean_returnvalue(core_message_external::get_unread_conversations_count_returns(),
3223             $result);
3225         $this->assertEquals(3, $result);
3226     }
3228     /**
3229      * Test getting unread conversation count as other user.
3230      */
3231     public function test_get_unread_conversations_count_as_other_user() {
3232         $this->resetAfterTest(true);
3234         // The person wanting the conversation count.
3235         $this->setAdminUser();
3237         // Create some users.
3238         $user1 = self::getDataGenerator()->create_user();
3239         $user2 = self::getDataGenerator()->create_user();
3240         $user3 = self::getDataGenerator()->create_user();
3241         $user4 = self::getDataGenerator()->create_user();
3243         // Send some messages back and forth, have some different conversations with different users.
3244         $this->send_message($user1, $user2, 'Yo!');
3245         $this->send_message($user2, $user1, 'Sup mang?');
3246         $this->send_message($user1, $user2, 'Writing PHPUnit tests!');
3247         $this->send_message($user2, $user1, 'Word.');
3249         $this->send_message($user1, $user3, 'Booyah');
3250         $this->send_message($user3, $user1, 'Whaaat?');
3251         $this->send_message($user1, $user3, 'Nothing.');
3252         $this->send_message($user3, $user1, 'Cool.');
3254         $this->send_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?');
3255         $this->send_message($user4, $user1, 'Yah brah, it\'s pretty rad.');
3256         $this->send_message($user1, $user4, 'Dope.');
3258         // Get the unread conversation count.
3259         $result = core_message_external::get_unread_conversations_count($user1->id);
3261         // We need to execute the return values cleaning process to simulate the web service server.
3262         $result = external_api::clean_returnvalue(core_message_external::get_unread_conversations_count_returns(),
3263             $result);
3265         $this->assertEquals(3, $result);
3266     }
3268     /**
3269      * Test getting unread conversation count as other user without proper capability.
3270      */
3271     public function test_get_unread_conversations_count_as_other_user_without_cap() {
3272         $this->resetAfterTest(true);
3274         // Create some users.
3275         $user1 = self::getDataGenerator()->create_user();
3276         $user2 = self::getDataGenerator()->create_user();
3278         // The person wanting the conversation count.
3279         $this->setUser($user1);
3281         // Ensure an exception is thrown.
3282         $this->expectException('moodle_exception');
3283         core_message_external::get_unread_conversations_count($user2->id);
3284     }
3286     /**
3287      * Test deleting conversations.
3288      */
3289     public function test_delete_conversations_by_id() {
3290         global $DB;
3292         $this->resetAfterTest(true);
3294         // Create some users.
3295         $user1 = self::getDataGenerator()->create_user();
3296         $user2 = self::getDataGenerator()->create_user();
3298         // The person wanting to delete the conversation.
3299         $this->setUser($user1);
3301         // Send some messages back and forth.
3302         $time = time();
3303         $m1id = $this->send_message($user1, $user2, 'Yo!', 0, $time);
3304         $m2id = $this->send_message($user2, $user1, 'Sup mang?', 0, $time + 1);
3305         $m3id = $this->send_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 2);
3306         $m4id = $this->send_message($user2, $user1, 'Word.', 0, $time + 3);
3308         $conversationid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
3310         // Delete the conversation.
3311         core_message_external::delete_conversations_by_id($user1->id, [$conversationid]);
3313         $muas = $DB->get_records('message_user_actions', array(), 'timecreated ASC');
3314         $this->assertCount(4, $muas);
3315         // Sort by id.
3316         ksort($muas);
3318         $mua1 = array_shift($muas);
3319         $mua2 = array_shift($muas);
3320         $mua3 = array_shift($muas);
3321         $mua4 = array_shift($muas);
3323         $this->assertEquals($user1->id, $mua1->userid);
3324         $this->assertEquals($m1id, $mua1->messageid);
3325         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua1->action);
3327         $this->assertEquals($user1->id, $mua2->userid);
3328         $this->assertEquals($m2id, $mua2->messageid);
3329         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua2->action);
3331         $this->assertEquals($user1->id, $mua3->userid);
3332         $this->assertEquals($m3id, $mua3->messageid);
3333         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua3->action);
3335         $this->assertEquals($user1->id, $mua4->userid);
3336         $this->assertEquals($m4id, $mua4->messageid);
3337         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua4->action);
3338     }
3340     /**
3341      * Test deleting conversations as other user.
3342      */
3343     public function test_delete_conversations_by_id_as_other_user() {
3344         global $DB;
3346         $this->resetAfterTest(true);
3348         $this->setAdminUser();
3350         // Create some users.
3351         $user1 = self::getDataGenerator()->create_user();
3352         $user2 = self::getDataGenerator()->create_user();
3354         // Send some messages back and forth.
3355         $time = time();
3356         $m1id = $this->send_message($user1, $user2, 'Yo!', 0, $time);
3357         $m2id = $this->send_message($user2, $user1, 'Sup mang?', 0, $time + 1);
3358         $m3id = $this->send_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 2);
3359         $m4id = $this->send_message($user2, $user1, 'Word.', 0, $time + 3);
3361         $conversationid = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]);
3363         // Delete the conversation.
3364         core_message_external::delete_conversations_by_id($user1->id, [$conversationid]);
3366         $muas = $DB->get_records('message_user_actions', array(), 'timecreated ASC');
3367         $this->assertCount(4, $muas);
3368         // Sort by id.
3369         ksort($muas);
3371         $mua1 = array_shift($muas);
3372         $mua2 = array_shift($muas);
3373         $mua3 = array_shift($muas);
3374         $mua4 = array_shift($muas);
3376         $this->assertEquals($user1->id, $mua1->userid);
3377         $this->assertEquals($m1id, $mua1->messageid);
3378         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua1->action);
3380         $this->assertEquals($user1->id, $mua2->userid);
3381         $this->assertEquals($m2id, $mua2->messageid);
3382         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua2->action);
3384         $this->assertEquals($user1->id, $mua3->userid);
3385         $this->assertEquals($m3id, $mua3->messageid);
3386         $this->assertEquals(\core_message\api::MESSAGE_ACTION_DELETED, $mua3->action);
3388         $this->assertEquals($user1->id, $mua4->userid);
3389         $this->assertEquals($m4id, $mua4->messageid);