diff --git a/message/classes/api.php b/message/classes/api.php index df6b6068de4..5111c37b120 100644 --- a/message/classes/api.php +++ b/message/classes/api.php @@ -1756,6 +1756,102 @@ class api { return $DB->record_exists('message_conversation_members', ['conversationid' => $conversationid, 'userid' => $userid]); + } + /** + * Add some new members to an existing conversation. + * + * @param array $userids User ids array to add as members. + * @param int $convid The conversation id. Must exists. + * @throws \dml_missing_record_exception If convid conversation doesn't exist + * @throws \dml_exception If there is a database error + */ + public static function add_members_to_conversation(array $userids, int $convid) { + global $DB; + + $conversation = $DB->get_record('message_conversations', ['id' => $convid], '*', MUST_EXIST); + + // Be sure we are not trying to add a non existing user to the conversation. Work only with existing users. + list($useridcondition, $params) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED); + $existingusers = array_keys($DB->get_records_select_menu('user', + "id $useridcondition", $params, 'id', 'id, id')); + + // Be sure we are not adding a user is already member of the conversation. Take all the members. + $memberuserids = array_values($DB->get_records_menu( + 'message_conversation_members', ['conversationid' => $convid], 'id', 'id, userid') + ); + + // Work with existing new members. + $members = array(); + $newuserids = array_diff($existingusers, $memberuserids); + foreach ($newuserids as $userid) { + $member = new \stdClass(); + $member->conversationid = $convid; + $member->userid = $userid; + $member->timecreated = time(); + $members[] = $member; + } + + $transaction = $DB->start_delegated_transaction(); + + $DB->insert_records('message_conversation_members', $members); + + // Hash is usefull only for 1-to-1 convs, so we don't update null conversation hashes. + if (isset($conversation->convhash)) { + // Getting all conversation members to create a new hash. + $newuserids = array_values($DB->get_records_menu( + 'message_conversation_members', ['conversationid' => $convid], 'id', 'id, userid') + ); + + $conversation->convhash = helper::get_conversation_hash($newuserids); + $DB->update_record('message_conversations', $conversation); + } + $transaction->allow_commit(); + } + + /** + * Remove some members from an existing conversation. + * + * @param array $userids The user ids to remove from conversation members. + * @param int $convid The conversation id. Must exists. + * @throws \dml_exception + */ + public static function remove_members_from_conversation(array $userids, int $convid) { + global $DB; + + $conversation = $DB->get_record('message_conversations', ['id' => $convid], '*', MUST_EXIST); + + list($useridcondition, $params) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED); + $params['convid'] = $convid; + + $transaction = $DB->start_delegated_transaction(); + + $DB->delete_records_select('message_conversation_members', + "conversationid = :convid AND userid $useridcondition", $params); + + // Hash is usefull only for 1-to-1 convs, so we don't update null conversation hashes. + if (isset($conversation->convhash)) { + // Getting all conversation members to create a new hash. + $newuserids = array_values($DB->get_records_menu( + 'message_conversation_members', ['conversationid' => $convid], 'id', 'id, userid') + ); + + $conversation->convhash = helper::get_conversation_hash($newuserids); + $DB->update_record('message_conversations', $conversation); + } + $transaction->allow_commit(); + } + + /** + * Count conversation members. + * + * @param int $convid The conversation id. + * @return int Number of conversation members. + * @throws \dml_exception + */ + public static function count_conversation_members(int $convid) : int { + global $DB; + + return $DB->count_records('message_conversation_members', ['conversationid' => $convid]); } } diff --git a/message/tests/api_test.php b/message/tests/api_test.php index 4b04fc4e1b7..8081a501252 100644 --- a/message/tests/api_test.php +++ b/message/tests/api_test.php @@ -2133,6 +2133,204 @@ class core_message_api_testcase extends core_message_messagelib_testcase { \core_message\api::get_conversation_between_users([$user1->id, $user2->id])); } + /** + * Test count_conversation_members for non existing conversation. + */ + public function test_count_conversation_members_no_existing_conversation() { + $this->assertEquals(0, + \core_message\api::count_conversation_members(0)); + } + + /** + * Test count_conversation_members for existing conversation. + */ + public function test_count_conversation_members_existing_conversation() { + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + + $conversationid = \core_message\api::create_conversation_between_users([$user1->id, $user2->id]); + + $this->assertEquals(2, + \core_message\api::count_conversation_members($conversationid)); + } + + /** + * Test add_members_to_conversation for existing conversation. + */ + public function test_add_members_to_existing_conversation() { + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + + $conversationid = \core_message\api::create_conversation_between_users([$user1->id, $user2->id]); + + $this->assertNull(\core_message\api::add_members_to_conversation([$user3->id], $conversationid)); + $this->assertEquals(3, + \core_message\api::count_conversation_members($conversationid)); + } + + /** + * Test add_members_to_conversation for non existing conversation. + */ + public function test_add_members_to_no_existing_conversation() { + $user1 = self::getDataGenerator()->create_user(); + + // Throw dml_missing_record_exception for non existing conversation. + $this->expectException('dml_missing_record_exception'); + \core_message\api::add_members_to_conversation([$user1->id], 0); + } + + /** + * Test add_member_to_conversation for non existing user. + */ + public function test_add_members_to_no_existing_user() { + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + + $conversationid = \core_message\api::create_conversation_between_users([$user1->id, $user2->id]); + + // Don't throw an error for non existing user, but don't add it as a member. + $this->assertNull(\core_message\api::add_members_to_conversation([0], $conversationid)); + $this->assertEquals(2, + \core_message\api::count_conversation_members($conversationid)); + } + + /** + * Test add_members_to_conversation for current conversation member. + */ + public function test_add_members_to_current_conversation_member() { + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + + $conversationid = \core_message\api::create_conversation_between_users([$user1->id, $user2->id]); + + // Don't add as a member a user that is already conversation member. + $this->assertNull(\core_message\api::add_members_to_conversation([$user1->id], $conversationid)); + $this->assertEquals(2, + \core_message\api::count_conversation_members($conversationid)); + } + + /** + * Test add_members_to_conversation for multiple users. + */ + public function test_add_members_for_multiple_users() { + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + $user4 = self::getDataGenerator()->create_user(); + + $conversationid = \core_message\api::create_conversation_between_users([$user1->id, $user2->id]); + + $this->assertNull(\core_message\api::add_members_to_conversation([$user3->id, $user4->id], $conversationid)); + $this->assertEquals(4, + \core_message\api::count_conversation_members($conversationid)); + } + + /** + * Test add_members_to_conversation for multiple users, included non existing and current conversation members + */ + public function test_add_members_for_multiple_not_valid_users() { + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + + $conversationid = \core_message\api::create_conversation_between_users([$user1->id, $user2->id]); + + // Don't throw errors, but don't add as members users don't exist or are already conversation members. + $this->assertNull(\core_message\api::add_members_to_conversation([$user3->id, $user1->id, 0], $conversationid)); + $this->assertEquals(3, + \core_message\api::count_conversation_members($conversationid)); + } + + /** + * Test remove_members_from_conversation for existing conversation. + */ + public function test_remove_members_from_existing_conversation() { + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + + $conversationid = \core_message\api::create_conversation_between_users([$user1->id, $user2->id]); + + $this->assertNull(\core_message\api::remove_members_from_conversation([$user1->id], $conversationid)); + $this->assertEquals(1, + \core_message\api::count_conversation_members($conversationid)); + } + + /** + * Test remove_members_from_conversation for non existing conversation. + */ + public function test_remove_members_from_no_existing_conversation() { + $user1 = self::getDataGenerator()->create_user(); + + // Throw dml_missing_record_exception for non existing conversation. + $this->expectException('dml_missing_record_exception'); + \core_message\api::remove_members_from_conversation([$user1->id], 0); + } + + /** + * Test remove_members_from_conversation for non existing user. + */ + public function test_remove_members_for_no_existing_user() { + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + + $conversationid = \core_message\api::create_conversation_between_users([$user1->id, $user2->id]); + + $this->assertNull(\core_message\api::remove_members_from_conversation([0], $conversationid)); + $this->assertEquals(2, + \core_message\api::count_conversation_members($conversationid)); + } + + /** + * Test remove_members_from_conversation for multiple users. + */ + public function test_remove_members_for_multiple_users() { + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + $user4 = self::getDataGenerator()->create_user(); + + $conversationid = \core_message\api::create_conversation_between_users([$user1->id, $user2->id]); + + $this->assertNull(\core_message\api::add_members_to_conversation([$user3->id, $user4->id], $conversationid)); + $this->assertNull(\core_message\api::remove_members_from_conversation([$user3->id, $user4->id], $conversationid)); + $this->assertEquals(2, + \core_message\api::count_conversation_members($conversationid)); + } + + /** + * Test remove_members_from_conversation for multiple non valid users. + */ + public function test_remove_members_for_multiple_no_valid_users() { + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + $user3 = self::getDataGenerator()->create_user(); + $user4 = self::getDataGenerator()->create_user(); + + $conversationid = \core_message\api::create_conversation_between_users([$user1->id, $user2->id]); + + $this->assertNull(\core_message\api::add_members_to_conversation([$user3->id], $conversationid)); + $this->assertNull( + \core_message\api::remove_members_from_conversation([$user2->id, $user3->id, $user4->id, 0], $conversationid) + ); + $this->assertEquals(1, + \core_message\api::count_conversation_members($conversationid)); + } + + /** + * Test count_conversation_members for empty conversation. + */ + public function test_count_conversation_members_empty_conversation() { + $user1 = self::getDataGenerator()->create_user(); + $user2 = self::getDataGenerator()->create_user(); + + $conversationid = \core_message\api::create_conversation_between_users([$user1->id, $user2->id]); + $this->assertNull(\core_message\api::remove_members_from_conversation([$user1->id, $user2->id], $conversationid)); + + $this->assertEquals(0, + \core_message\api::count_conversation_members($conversationid)); + } + /** * Test can create a contact request. */