From b8ff2c4481c23050d55af0678022b8d9a0825f63 Mon Sep 17 00:00:00 2001 From: Jake Dallimore Date: Mon, 22 Oct 2018 09:25:59 +0800 Subject: [PATCH 1/2] MDL-63213 core_message: update get_conversations to support favourites Added the type param here, which will be used in MDL-63549. --- message/classes/api.php | 60 +++++++- message/tests/api_test.php | 298 +++++++++++++++++++++++++++++++++++++ 2 files changed, 354 insertions(+), 4 deletions(-) diff --git a/message/classes/api.php b/message/classes/api.php index d9b507edb40..992afe2e67b 100644 --- a/message/classes/api.php +++ b/message/classes/api.php @@ -24,6 +24,8 @@ namespace core_message; +use core_favourites\local\entity\favourite; + defined('MOODLE_INTERNAL') || die(); require_once($CFG->dirroot . '/lib/messagelib.php'); @@ -274,11 +276,31 @@ class api { * @param int $userid The user id * @param int $limitfrom * @param int $limitnum + * @param int $type the conversation type. + * @param bool $favouritesonly whether to retrieve only the favourite conversations for the user, or not. * @return array */ - public static function get_conversations($userid, $limitfrom = 0, $limitnum = 20) { + public static function get_conversations($userid, $limitfrom = 0, $limitnum = 20, int $type = null, + bool $favouritesonly = false) { global $DB; + $favouritesql = ""; + $favouriteparams = []; + if ($favouritesonly) { + // Ask the favourites subsystem for the user's favourite conversations. + $service = \core_favourites\service_factory::get_service_for_user_context(\context_user::instance($userid)); + $favourites = $service->find_favourites_by_type('core_message', 'message_conversations'); + if (empty($favourites)) { + return []; // No favourited conversations, so return none. + } + $favids = array_values(array_map(function ($fav) { + return $fav->itemid; + }, $favourites)); + list ($insql, $inparams) = $DB->get_in_or_equal($favids, SQL_PARAMS_NAMED, 'favouriteids'); + $favouritesql = " AND m.conversationid {$insql} "; + $favouriteparams = $inparams; + } + // Get the last message from each conversation that the user belongs to. $sql = "SELECT m.id, m.conversationid, m.useridfrom, mcm2.userid as useridto, m.smallmessage, m.timecreated FROM {messages} m @@ -305,10 +327,12 @@ class api { INNER JOIN {message_conversation_members} mcm2 ON mcm2.conversationid = m.conversationid WHERE mcm.userid = m.useridfrom - AND mcm.id != mcm2.id + AND mcm.id != mcm2.id $favouritesql ORDER BY m.timecreated DESC"; - $messageset = $DB->get_recordset_sql($sql, ['userid' => $userid, 'action' => self::MESSAGE_ACTION_DELETED, - 'userid2' => $userid], $limitfrom, $limitnum); + + $params = array_merge($favouriteparams, ['userid' => $userid, 'action' => self::MESSAGE_ACTION_DELETED, + 'userid2' => $userid]); + $messageset = $DB->get_recordset_sql($sql, $params, $limitfrom, $limitnum); $messages = []; foreach ($messageset as $message) { @@ -409,6 +433,34 @@ class api { return $arrconversations; } + /** + * Mark a conversation as a favourite for the given user. + * + * @param int $conversationid the id of the conversation to mark as a favourite. + * @param int $userid the id of the user to whom the favourite belongs. + * @return favourite the favourite object. + * @throws \moodle_exception if the user or conversation don't exist. + */ + public static function set_favourite_conversation(int $conversationid, int $userid) : favourite { + if (!self::is_user_in_conversation($userid, $conversationid)) { + throw new \moodle_exception("Conversation doesn't exist or user is not a member"); + } + $ufservice = \core_favourites\service_factory::get_service_for_user_context(\context_user::instance($userid)); + return $ufservice->create_favourite('core_message', 'message_conversations', $conversationid, \context_system::instance()); + } + + /** + * Unset a conversation as a favourite for the given user. + * + * @param int $conversationid the id of the conversation to unset as a favourite. + * @param int $userid the id to whom the favourite belongs. + * @throws \moodle_exception if the favourite does not exist for the user. + */ + public static function unset_favourite_conversation(int $conversationid, int $userid) { + $ufservice = \core_favourites\service_factory::get_service_for_user_context(\context_user::instance($userid)); + $ufservice->delete_favourite('core_message', 'message_conversations', $conversationid, \context_system::instance()); + } + /** * Returns the contacts to display in the contacts area. * diff --git a/message/tests/api_test.php b/message/tests/api_test.php index 8be0f3f6070..23ad644adf4 100644 --- a/message/tests/api_test.php +++ b/message/tests/api_test.php @@ -341,6 +341,304 @@ class core_message_api_testcase extends core_message_messagelib_testcase { $this->assertNull($message3->unreadcount); } + /** + * Test verifying that favourited conversations can be retrieved. + */ + public function test_get_favourite_conversations() { + // Create some users. + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + $user4 = self::getDataGenerator()->create_user(); + + // The person doing the search. + $this->setUser($user1); + + // No conversations yet. + $this->assertEquals([], \core_message\api::get_conversations($user1->id)); + + // Create some conversations for user1. + $time = 1; + $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1); + $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2); + $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3); + $messageid1 = $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4); + + $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5); + $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6); + $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7); + $messageid2 = $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8); + + $this->send_fake_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?', 0, $time + 9); + $this->send_fake_message($user4, $user1, 'Yah brah, it\'s pretty rad.', 0, $time + 10); + $messageid3 = $this->send_fake_message($user1, $user4, 'Dope.', 0, $time + 11); + + // Favourite the first 2 conversations for user1. + $convoids = []; + $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]); + $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]); + $user1context = context_user::instance($user1->id); + $service = \core_favourites\service_factory::get_service_for_user_context($user1context); + foreach ($convoids as $convoid) { + $service->create_favourite('core_message', 'message_conversations', $convoid, $user1context); + } + + // We should have 3 conversations. + $this->assertCount(3, \core_message\api::get_conversations($user1->id)); + + // And 2 favourited conversations. + $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, true); + $this->assertCount(2, $conversations); + } + + /** + * Tests retrieving favourite conversations with a limit and offset to ensure pagination works correctly. + */ + public function test_get_favourite_conversations_limit_offset() { + // Create some users. + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + $user4 = self::getDataGenerator()->create_user(); + + // The person doing the search. + $this->setUser($user1); + + // No conversations yet. + $this->assertEquals([], \core_message\api::get_conversations($user1->id)); + + // Create some conversations for user1. + $time = 1; + $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1); + $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2); + $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3); + $messageid1 = $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4); + + $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5); + $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6); + $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7); + $messageid2 = $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8); + + $this->send_fake_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?', 0, $time + 9); + $this->send_fake_message($user4, $user1, 'Yah brah, it\'s pretty rad.', 0, $time + 10); + $messageid3 = $this->send_fake_message($user1, $user4, 'Dope.', 0, $time + 11); + + // Favourite the all conversations for user1. + $convoids = []; + $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]); + $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]); + $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user4->id]); + $user1context = context_user::instance($user1->id); + $service = \core_favourites\service_factory::get_service_for_user_context($user1context); + foreach ($convoids as $convoid) { + $service->create_favourite('core_message', 'message_conversations', $convoid, $user1context); + } + + // Get all records, using offset 0 and large limit. + $this->assertCount(2, \core_message\api::get_conversations($user1->id, 1, 10, null, true)); + + // Now, get 10 conversations starting at the second record. We should see 2 conversations. + $this->assertCount(2, \core_message\api::get_conversations($user1->id, 1, 10, null, true)); + + // Now, try to get favourited conversations using an invalid offset. + $this->assertCount(0, \core_message\api::get_conversations($user1->id, 4, 10, null, true)); + } + + /** + * Tests retrieving favourite conversations when a conversation contains a deleted user. + */ + public function test_get_favourite_conversations_with_deleted_user() { + // Create some users. + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + + // Send some messages back and forth, have some different conversations with different users. + $time = 1; + $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1); + $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2); + $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3); + $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4); + + $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5); + $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6); + $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7); + $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8); + + // Favourite the all conversations for user1. + $convoids = []; + $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]); + $convoids[] = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]); + $user1context = context_user::instance($user1->id); + $service = \core_favourites\service_factory::get_service_for_user_context($user1context); + foreach ($convoids as $convoid) { + $service->create_favourite('core_message', 'message_conversations', $convoid, $user1context); + } + + // Delete the second user. + delete_user($user2); + + // Retrieve the conversations. + $conversations = \core_message\api::get_conversations($user1->id, 0, 20, null, true); + + // We should only have one conversation because the other user was deleted. + $this->assertCount(1, $conversations); + + // Confirm the conversation is from the non-deleted user. + $conversation = reset($conversations); + $this->assertEquals($user3->id, $conversation->userid); + } + + /** + * Test confirming that conversations can be marked as favourites. + */ + public function test_set_favourite_conversation() { + // Create some users. + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + + // Send some messages back and forth, have some different conversations with different users. + $time = 1; + $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1); + $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2); + $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3); + $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4); + + $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5); + $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6); + $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7); + $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8); + + // Favourite the first conversation as user 1. + $conversationid1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]); + \core_message\api::set_favourite_conversation($conversationid1, $user1->id); + + // Verify we have a single favourite conversation a user 1. + $this->assertCount(1, \core_message\api::get_conversations($user1->id, 0, 20, null, true)); + + // Verify we have no favourites as user2, despite being a member in that conversation. + $this->assertCount(0, \core_message\api::get_conversations($user2->id, 0, 20, null, true)); + + // Try to favourite the same conversation again. + $this->expectException(\moodle_exception::class); + \core_message\api::set_favourite_conversation($conversationid1, $user1->id); + } + + /** + * Test verifying that trying to mark a non-existent conversation as a favourite, results in an exception. + */ + public function test_set_favourite_conversation_nonexistent_conversation() { + // Create some users. + $user1 = self::getDataGenerator()->create_user(); + // Try to favourite a non-existent conversation. + $this->expectException(\moodle_exception::class); + \core_message\api::set_favourite_conversation(0, $user1->id); + } + + /** + * Test verifying that a conversation cannot be marked as favourite unless the user is a member of that conversation. + */ + public function test_set_favourite_conversation_non_member() { + // Create some users. + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + + // Send some messages back and forth, have some different conversations with different users. + $time = 1; + $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1); + $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2); + $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3); + $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4); + + $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5); + $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6); + $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7); + $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8); + + // Try to favourite the first conversation as user 3, who is not a member. + $conversationid1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]); + $this->expectException(\moodle_exception::class); + \core_message\api::set_favourite_conversation($conversationid1, $user3->id); + } + + /** + * Test confirming that those conversations marked as favourites can be unfavourited. + */ + public function test_unset_favourite_conversation() { + // Create some users. + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + + // Send some messages back and forth, have some different conversations with different users. + $time = 1; + $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1); + $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2); + $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3); + $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4); + + $this->send_fake_message($user1, $user3, 'Booyah', 0, $time + 5); + $this->send_fake_message($user3, $user1, 'Whaaat?', 0, $time + 6); + $this->send_fake_message($user1, $user3, 'Nothing.', 0, $time + 7); + $this->send_fake_message($user3, $user1, 'Cool.', 0, $time + 8); + + // Favourite the first conversation as user 1 and the second as user 3. + $conversationid1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]); + $conversationid2 = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]); + \core_message\api::set_favourite_conversation($conversationid1, $user1->id); + \core_message\api::set_favourite_conversation($conversationid2, $user3->id); + + // Verify we have a single favourite conversation for both user 1 and user 3. + $this->assertCount(1, \core_message\api::get_conversations($user1->id, 0, 20, null, true)); + $this->assertCount(1, \core_message\api::get_conversations($user3->id, 0, 20, null, true)); + + // Now unfavourite the conversation as user 1. + \core_message\api::unset_favourite_conversation($conversationid1, $user1->id); + + // Verify we have a single favourite conversation user 3 only, and none for user1. + $this->assertCount(1, \core_message\api::get_conversations($user3->id, 0, 20, null, true)); + $this->assertCount(0, \core_message\api::get_conversations($user1->id, 0, 20, null, true)); + + // Try to favourite the same conversation again as user 1. + $this->expectException(\moodle_exception::class); + \core_message\api::unset_favourite_conversation($conversationid1, $user1->id); + } + + /** + * Test verifying that a valid conversation cannot be unset as a favourite if it's not marked as a favourite. + */ + public function test_unset_favourite_conversation_not_favourite() { + // Create some users. + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + + // Send some messages back and forth, have some different conversations with different users. + $time = 1; + $this->send_fake_message($user1, $user2, 'Yo!', 0, $time + 1); + $this->send_fake_message($user2, $user1, 'Sup mang?', 0, $time + 2); + $this->send_fake_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 3); + $this->send_fake_message($user2, $user1, 'Word.', 0, $time + 4); + + // Now try to unfavourite the conversation as user 1. + $conversationid1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]); + $this->expectException(\moodle_exception::class); + \core_message\api::unset_favourite_conversation($conversationid1, $user1->id); + } + + /** + * Test verifying that a non-existent conversation cannot be unset as a favourite. + */ + public function test_unset_favourite_conversation_non_existent_conversation() { + // Create some users. + $user1 = self::getDataGenerator()->create_user(); + + // Now try to unfavourite the conversation as user 1. + $this->expectException(\moodle_exception::class); + \core_message\api::unset_favourite_conversation(0, $user1->id); + } + /** * Tests retrieving conversations. */ From 5b367baef85f3151c6b04f0e0a6f1fbfcd44a565 Mon Sep 17 00:00:00 2001 From: Jake Dallimore Date: Mon, 22 Oct 2018 09:42:01 +0800 Subject: [PATCH 2/2] MDL-63213 core_message: add web services for set/unset favourites --- lib/db/services.php | 16 +++ message/externallib.php | 118 +++++++++++++++++ message/tests/externallib_test.php | 195 +++++++++++++++++++++++++++++ 3 files changed, 329 insertions(+) diff --git a/lib/db/services.php b/lib/db/services.php index 5cec94e4616..5a7fbbe2bb4 100644 --- a/lib/db/services.php +++ b/lib/db/services.php @@ -1154,6 +1154,22 @@ $functions = array( 'capabilities' => 'moodle/user:editownmessageprofile', 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE), ), + 'core_message_set_favourite_conversations' => array( + 'classname' => 'core_message_external', + 'methodname' => 'set_favourite_conversations', + 'classpath' => 'message/externallib.php', + 'description' => 'Mark a conversation or group of conversations as favourites/starred conversations.', + 'type' => 'write', + 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE), + ), + 'core_message_unset_favourite_conversations' => array( + 'classname' => 'core_message_external', + 'methodname' => 'unset_favourite_conversations', + 'classpath' => 'message/externallib.php', + 'description' => 'Unset a conversation or group of conversations as favourites/starred conversations.', + 'type' => 'write', + 'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE), + ), 'core_notes_create_notes' => array( 'classname' => 'core_notes_external', 'methodname' => 'create_notes', diff --git a/message/externallib.php b/message/externallib.php index 89016ecb451..2936f21603d 100644 --- a/message/externallib.php +++ b/message/externallib.php @@ -3137,4 +3137,122 @@ class core_message_external extends external_api { ) ); } + + /** + * Returns description of method parameters for the favourite_conversations() method. + * + * @return external_function_parameters + */ + public static function set_favourite_conversations_parameters() { + return new external_function_parameters( + array( + 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0), + 'conversations' => new external_multiple_structure( + new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0) + ) + ) + ); + } + + /** + * Favourite a conversation, or list of conversations for a user. + * + * @param int $userid the id of the user, or 0 for the current user. + * @param array $conversationids the list of conversations ids to favourite. + * @return array + * @throws moodle_exception if messaging is disabled or if the user cannot perform the action. + */ + public static function set_favourite_conversations(int $userid, array $conversationids) { + global $CFG, $USER; + + // All the business logic checks that really shouldn't be in here. + if (empty($CFG->messaging)) { + throw new moodle_exception('disabled', 'message'); + } + $params = [ + 'userid' => $userid, + 'conversations' => $conversationids + ]; + $params = self::validate_parameters(self::set_favourite_conversations_parameters(), $params); + $systemcontext = context_system::instance(); + self::validate_context($systemcontext); + + if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) { + throw new moodle_exception('You do not have permission to perform this action.'); + } + + foreach ($params['conversations'] as $conversationid) { + \core_message\api::set_favourite_conversation($conversationid, $params['userid']); + } + + return []; + } + + /** + * Return a description of the returns for the create_user_favourite_conversations() method. + * + * @return external_description + */ + public static function set_favourite_conversations_returns() { + return new external_warnings(); + } + + /** + * Returns description of method parameters for unfavourite_conversations() method. + * + * @return external_function_parameters + */ + public static function unset_favourite_conversations_parameters() { + return new external_function_parameters( + array( + 'userid' => new external_value(PARAM_INT, 'id of the user, 0 for current user', VALUE_DEFAULT, 0), + 'conversations' => new external_multiple_structure( + new external_value(PARAM_INT, 'id of the conversation', VALUE_DEFAULT, 0) + ) + ) + ); + } + + /** + * Unfavourite a conversation, or list of conversations for a user. + * + * @param int $userid the id of the user, or 0 for the current user. + * @param array $conversationids the list of conversations ids unset as favourites. + * @return array + * @throws moodle_exception if messaging is disabled or if the user cannot perform the action. + */ + public static function unset_favourite_conversations(int $userid, array $conversationids) { + global $CFG, $USER; + + // All the business logic checks that really shouldn't be in here. + if (empty($CFG->messaging)) { + throw new moodle_exception('disabled', 'message'); + } + $params = [ + 'userid' => $userid, + 'conversations' => $conversationids + ]; + $params = self::validate_parameters(self::unset_favourite_conversations_parameters(), $params); + $systemcontext = context_system::instance(); + self::validate_context($systemcontext); + + if (($USER->id != $userid) && !has_capability('moodle/site:readallmessages', $systemcontext)) { + throw new moodle_exception('You do not have permission to perform this action.'); + } + + foreach ($params['conversations'] as $conversationid) { + \core_message\api::unset_favourite_conversation($conversationid, $params['userid']); + } + + return []; + } + + /** + * Unset favourite conversations return description. + * + * @return external_description + */ + public static function unset_favourite_conversations_returns() { + return new external_warnings(); + } } diff --git a/message/tests/externallib_test.php b/message/tests/externallib_test.php index aa7f61f8d52..2665af2f8b9 100644 --- a/message/tests/externallib_test.php +++ b/message/tests/externallib_test.php @@ -3752,4 +3752,199 @@ class core_message_externallib_testcase extends externallib_advanced_testcase { protected static function sort_contacts($a, $b) { return $a['userid'] > $b['userid']; } + + /** + * Test verifying that conversations can be marked as favourite conversations. + */ + public function test_set_favourite_conversations_basic() { + $this->resetAfterTest(); + + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + $user4 = self::getDataGenerator()->create_user(); + + $this->setUser($user1); + + // Now, create some conversations. + $time = time(); + $this->send_message($user1, $user2, 'Yo!', 0, $time); + $this->send_message($user2, $user1, 'Sup mang?', 0, $time + 1); + $this->send_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 2); + + $this->send_message($user1, $user3, 'Booyah'); + $this->send_message($user3, $user1, 'Whaaat?'); + $this->send_message($user1, $user3, 'Nothing.'); + + $this->send_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?'); + $this->send_message($user4, $user1, 'Yah brah, it\'s pretty rad.'); + + // Favourite 2 conversations as user 1. + $conversation1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]); + $conversation2 = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]); + $result = core_message_external::set_favourite_conversations($user1->id, [$conversation1, $conversation2]); + + // We need to execute the return values cleaning process to simulate the web service server. + $result = external_api::clean_returnvalue(core_message_external::set_favourite_conversations_returns(), $result); + $this->assertCount(0, $result); + } + + /** + * Test confirming that a user can't favourite a conversation on behalf of another user. + */ + public function test_set_favourite_conversations_another_users_conversation() { + $this->resetAfterTest(); + + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + + $this->setUser($user3); + + // Now, create some conversations. + $time = time(); + $this->send_message($user1, $user2, 'Yo!', 0, $time); + $this->send_message($user2, $user1, 'Sup mang?', 0, $time + 1); + $this->send_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 2); + + $this->send_message($user1, $user3, 'Booyah'); + $this->send_message($user3, $user1, 'Whaaat?'); + $this->send_message($user1, $user3, 'Nothing.'); + + // Try to favourite conversation 1 for user 2, as user3. + $conversation1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]); + $this->expectException(\moodle_exception::class); + $result = core_message_external::set_favourite_conversations($user2->id, [$conversation1]); + } + + /** + * Test confirming that a user can't mark a conversation as their own favourite if it's a conversation they're not a member of. + */ + public function test_set_favourite_conversations_non_member() { + $this->resetAfterTest(); + + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + + $this->setUser($user3); + + // Now, create some conversations. + $time = time(); + $this->send_message($user1, $user2, 'Yo!', 0, $time); + $this->send_message($user2, $user1, 'Sup mang?', 0, $time + 1); + $this->send_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 2); + + $this->send_message($user1, $user3, 'Booyah'); + $this->send_message($user3, $user1, 'Whaaat?'); + $this->send_message($user1, $user3, 'Nothing.'); + + // Try to favourite conversation 1 as user 3. + $conversation1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]); + $conversation2 = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]); + $this->expectException(\moodle_exception::class); + $result = core_message_external::set_favourite_conversations($user3->id, [$conversation1]); + } + + /** + * Test confirming that a user can't favourite a non-existent conversation. + */ + public function test_set_favourite_conversations_non_existent_conversation() { + $this->resetAfterTest(); + + $user1 = self::getDataGenerator()->create_user(); + $this->setUser($user1); + + // Try to favourite a non-existent conversation. + $this->expectException(\moodle_exception::class); + $result = core_message_external::set_favourite_conversations($user1->id, [0]); + } + + /** + * Test confirming that a user can unset a favourite conversation, or list of favourite conversations. + */ + public function test_unset_favourite_conversations_basic() { + $this->resetAfterTest(); + + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + $user4 = self::getDataGenerator()->create_user(); + + $this->setUser($user1); + + // Now, create some conversations. + $time = time(); + $this->send_message($user1, $user2, 'Yo!', 0, $time); + $this->send_message($user2, $user1, 'Sup mang?', 0, $time + 1); + $this->send_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 2); + + $this->send_message($user1, $user3, 'Booyah'); + $this->send_message($user3, $user1, 'Whaaat?'); + $this->send_message($user1, $user3, 'Nothing.'); + + $this->send_message($user1, $user4, 'Hey mate, you see the new messaging UI in Moodle?'); + $this->send_message($user4, $user1, 'Yah brah, it\'s pretty rad.'); + + // Favourite 2 conversations as user 1. + $conversation1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]); + $conversation2 = \core_message\api::get_conversation_between_users([$user1->id, $user3->id]); + \core_message\api::set_favourite_conversation($conversation1, $user1->id); + \core_message\api::set_favourite_conversation($conversation2, $user1->id); + $this->assertCount(2, \core_message\api::get_conversations($user1->id, 0, 20, null, true)); + + // Now, using the web service, unset the favourite conversations. + $result = core_message_external::unset_favourite_conversations($user1->id, [$conversation1, $conversation2]); + + // We need to execute the return values cleaning process to simulate the web service server. + $result = external_api::clean_returnvalue(core_message_external::unset_favourite_conversations_returns(), $result); + $this->assertCount(0, $result); + } + + /** + * Test confirming that a user can't unfavourite a conversation for another user. + */ + public function test_unset_favourite_conversations_another_users_conversation() { + $this->resetAfterTest(); + + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + + $this->setUser($user3); + + // Now, create some conversations. + $time = time(); + $this->send_message($user1, $user2, 'Yo!', 0, $time); + $this->send_message($user2, $user1, 'Sup mang?', 0, $time + 1); + $this->send_message($user1, $user2, 'Writing PHPUnit tests!', 0, $time + 2); + + $this->send_message($user1, $user3, 'Booyah'); + $this->send_message($user3, $user1, 'Whaaat?'); + $this->send_message($user1, $user3, 'Nothing.'); + + // Favourite conversation 1 for user1. The current user ($USER) isn't checked for this action. + $conversation1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]); + \core_message\api::set_favourite_conversation($conversation1, $user1->id); + $this->assertCount(1, \core_message\api::get_conversations($user1->id, 0, 20, null, true)); + + // Try to unfavourite conversation 1 for user 2, as user3. + $conversation1 = \core_message\api::get_conversation_between_users([$user1->id, $user2->id]); + $this->expectException(\moodle_exception::class); + $result = core_message_external::unset_favourite_conversations($user2->id, [$conversation1]); + } + + /** + * Test confirming that a user can't unfavourite a non-existent conversation. + */ + public function test_unset_favourite_conversations_non_existent_conversation() { + $this->resetAfterTest(); + + $user1 = self::getDataGenerator()->create_user(); + $this->setUser($user1); + + // Try to unfavourite a non-existent conversation. + $this->expectException(\moodle_exception::class); + $result = core_message_external::unset_favourite_conversations($user1->id, [0]); + } }