From 388c7c4363ec4a75eebe1ad5f767a87840c7aba6 Mon Sep 17 00:00:00 2001 From: cameronvoell Date: Thu, 30 May 2024 14:36:44 -0700 Subject: [PATCH] Added ios side and new test for super admin remove --- example/ios/Podfile.lock | 2 +- example/src/tests/groupPermissionsTests.ts | 87 ++++++++++++++++++++++ ios/XMTPModule.swift | 84 ++++++++++++++++++++- 3 files changed, 170 insertions(+), 3 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index cf4d1d6ee..64e25a2a5 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -769,4 +769,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 95d6ace79946933ecf80684613842ee553dd76a2 -COCOAPODS: 1.14.2 +COCOAPODS: 1.15.2 diff --git a/example/src/tests/groupPermissionsTests.ts b/example/src/tests/groupPermissionsTests.ts index 8ac250c0a..9b2cc78b9 100644 --- a/example/src/tests/groupPermissionsTests.ts +++ b/example/src/tests/groupPermissionsTests.ts @@ -229,3 +229,90 @@ test('in admin only group, members can not update group name after admin status // throw new Error('Expected exception when non-admin attempts to update group name.') return true }) + +test('can not remove a super admin from a group', async () => { + // Create clients + const [alix, bo] = await createClients(3) + + // Alix Create a group + const alixGroup = await alix.conversations.newGroup( + [bo.address], + 'all_members' + ) + + let alixIsSuperAdmin = await alixGroup.isSuperAdmin(alix.inboxId) + let boIsSuperAdmin = await alixGroup.isSuperAdmin(bo.inboxId) + let numMembers = (await alixGroup.memberInboxIds()).length + assert(alixIsSuperAdmin, `alix should be a super admin`) + assert(!boIsSuperAdmin, `bo should not be a super admin`) + assert( + numMembers === 2, + `number of members should be 2 but was ${numMembers}` + ) + + await bo.conversations.syncGroups() + const boGroup = (await bo.conversations.listGroups())[0] + await boGroup.sync() + + // Bo should not be able to remove alix from the group + try { + await boGroup.removeMembersByInboxId([alix.inboxId]) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (error) { + // expected + } + + await boGroup.sync() + numMembers = (await alixGroup.memberInboxIds()).length + assert(alixIsSuperAdmin, `alix should be a super admin`) + assert(!boIsSuperAdmin, `bo should not be a super admin`) + assert( + numMembers === 2, + `number of members should be 2 but was ${numMembers}` + ) + + // Alix adds bo as a super admin + await alixGroup.addSuperAdmin(bo.inboxId) + await alixGroup.sync() + boIsSuperAdmin = await alixGroup.isSuperAdmin(bo.inboxId) + assert(boIsSuperAdmin, `bo should be a super admin`) + await boGroup.sync() + boIsSuperAdmin = await boGroup.isSuperAdmin(bo.inboxId) + assert(boIsSuperAdmin, `bo should be a super admin`) + + // Uncommenting below causes an error + // intent 3 has reached max publish attempts + // error publishing intents CreateGroupContextExtProposalError(MlsGroupStateError(PendingCommit)) + // try { + // await boGroup.removeMembersByInboxId([alix.inboxId]) + // } catch (error) { + // // expected + // } + await boGroup.sync() + await alixGroup.sync() + numMembers = (await alixGroup.memberInboxIds()).length + assert( + numMembers === 2, + `number of members should be 2 but was ${numMembers}` + ) + + // Bo can remove alix as a super admin + await boGroup.sync() + await boGroup.removeSuperAdmin(alix.inboxId) + await boGroup.sync() + await alixGroup.sync() + alixIsSuperAdmin = await alixGroup.isSuperAdmin(alix.inboxId) + assert(!alixIsSuperAdmin, `alix should not be a super admin`) + + // Now bo can remove Alix from the group + await boGroup.removeMembers([alix.address]) + console.log('alix inbox id:' + String(alix.inboxId)) + await boGroup.sync() + numMembers = (await boGroup.memberInboxIds()).length + assert( + numMembers === 1, + `number of members should be 1 but was ${numMembers}` + ) + + return true +}) diff --git a/ios/XMTPModule.swift b/ios/XMTPModule.swift index 02f1287fa..c35ad5755 100644 --- a/ios/XMTPModule.swift +++ b/ios/XMTPModule.swift @@ -805,7 +805,7 @@ public class XMTPModule: Module { return try group.addedByInboxId() } - AsyncFunction("isGroupAdmin") { (clientAddress: String, id: String) -> Bool in + AsyncFunction("creatorInboxId") { (clientAddress: String, id: String) -> String in guard let client = await clientsManager.getClient(key: clientAddress) else { throw Error.noClient } @@ -813,7 +813,87 @@ public class XMTPModule: Module { throw Error.conversationNotFound("no group found for \(id)") } - return try group.isAdmin(inboxId: client.inboxID) + return try group.creatorInboxId() + } + + AsyncFunction("isAdmin") { (clientAddress: String, id: String, inboxId: String) -> Bool in + guard let client = await clientsManager.getClient(key: clientAddress) else { + throw Error.noClient + } + guard let group = try await findGroup(clientAddress: clientAddress, id: id) else { + throw Error.conversationNotFound("no group found for \(id)") + } + return try group.isAdmin(inboxId: inboxId) + } + + AsyncFunction("isSuperAdmin") { (clientAddress: String, id: String, inboxId: String) -> Bool in + guard let client = await clientsManager.getClient(key: clientAddress) else { + throw Error.noClient + } + guard let group = try await findGroup(clientAddress: clientAddress, id: id) else { + throw Error.conversationNotFound("no group found for \(id)") + } + return try group.isSuperAdmin(inboxId: inboxId) + } + + AsyncFunction("listAdmins") { (clientAddress: String, id: String) -> [String] in + guard let client = await clientsManager.getClient(key: clientAddress) else { + throw Error.noClient + } + guard let group = try await findGroup(clientAddress: clientAddress, id: id) else { + throw Error.conversationNotFound("no group found for \(id)") + } + return try group.listAdmins() + } + + AsyncFunction("listSuperAdmins") { (clientAddress: String, id: String) -> [String] in + guard let client = await clientsManager.getClient(key: clientAddress) else { + throw Error.noClient + } + guard let group = try await findGroup(clientAddress: clientAddress, id: id) else { + throw Error.conversationNotFound("no group found for \(id)") + } + return try group.listSuperAdmins() + } + + AsyncFunction("addAdmin") { (clientAddress: String, id: String, inboxId: String) in + guard let client = await clientsManager.getClient(key: clientAddress) else { + throw Error.noClient + } + guard let group = try await findGroup(clientAddress: clientAddress, id: id) else { + throw Error.conversationNotFound("no group found for \(id)") + } + try await group.addAdmin(inboxId: inboxId) + } + + AsyncFunction("addSuperAdmin") { (clientAddress: String, id: String, inboxId: String) in + guard let client = await clientsManager.getClient(key: clientAddress) else { + throw Error.noClient + } + guard let group = try await findGroup(clientAddress: clientAddress, id: id) else { + throw Error.conversationNotFound("no group found for \(id)") + } + try await group.addSuperAdmin(inboxId: inboxId) + } + + AsyncFunction("removeAdmin") { (clientAddress: String, id: String, inboxId: String) in + guard let client = await clientsManager.getClient(key: clientAddress) else { + throw Error.noClient + } + guard let group = try await findGroup(clientAddress: clientAddress, id: id) else { + throw Error.conversationNotFound("no group found for \(id)") + } + try await group.removeAdmin(inboxId: inboxId) + } + + AsyncFunction("removeSuperAdmin") { (clientAddress: String, id: String, inboxId: String) in + guard let client = await clientsManager.getClient(key: clientAddress) else { + throw Error.noClient + } + guard let group = try await findGroup(clientAddress: clientAddress, id: id) else { + throw Error.conversationNotFound("no group found for \(id)") + } + try await group.removeSuperAdmin(inboxId: inboxId) } AsyncFunction("processGroupMessage") { (clientAddress: String, id: String, encryptedMessage: String) -> String in