Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Group Admin Permissions #182

Merged
merged 6 commits into from
Feb 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import org.xmtp.android.library.codecs.ReactionSchema
import org.xmtp.android.library.messages.PrivateKey
import org.xmtp.android.library.messages.PrivateKeyBuilder
import org.xmtp.android.library.messages.walletAddress
import uniffi.xmtpv3.GroupPermissions

@RunWith(AndroidJUnit4::class)
class GroupTest {
Expand Down Expand Up @@ -57,9 +58,63 @@ class GroupTest {
}

@Test
fun testCanCreateAGroup() {
val group = boClient.conversations.newGroup(listOf(alix.walletAddress))
assert(group.id.isNotEmpty())
fun testCanCreateAGroupWithDefaultPermissions() {
val boGroup = boClient.conversations.newGroup(listOf(alix.walletAddress))
runBlocking { alixClient.conversations.syncGroups() }
val alixGroup = alixClient.conversations.listGroups().first()
assert(boGroup.id.isNotEmpty())
assert(alixGroup.id.isNotEmpty())

alixGroup.addMembers(listOf(caro.walletAddress))
runBlocking { boGroup.sync() }
assertEquals(alixGroup.memberAddresses().size, 3)
assertEquals(boGroup.memberAddresses().size, 3)

alixGroup.removeMembers(listOf(caro.walletAddress))
runBlocking { boGroup.sync() }
assertEquals(alixGroup.memberAddresses().size, 2)
assertEquals(boGroup.memberAddresses().size, 2)

boGroup.addMembers(listOf(caro.walletAddress))
runBlocking { alixGroup.sync() }
assertEquals(alixGroup.memberAddresses().size, 3)
assertEquals(boGroup.memberAddresses().size, 3)
}

@Test
fun testCanCreateAGroupWithAdminPermissions() {
val boGroup = boClient.conversations.newGroup(
listOf(alix.walletAddress),
permissions = GroupPermissions.GROUP_CREATOR_IS_ADMIN
)
runBlocking { alixClient.conversations.syncGroups() }
val alixGroup = alixClient.conversations.listGroups().first()
assert(boGroup.id.isNotEmpty())
assert(alixGroup.id.isNotEmpty())

boGroup.addMembers(listOf(caro.walletAddress))
runBlocking { alixGroup.sync() }
assertEquals(alixGroup.memberAddresses().size, 3)
assertEquals(boGroup.memberAddresses().size, 3)

assertThrows(XMTPException::class.java) {
alixGroup.removeMembers(listOf(caro.walletAddress))
}
runBlocking { boGroup.sync() }
assertEquals(alixGroup.memberAddresses().size, 3)
assertEquals(boGroup.memberAddresses().size, 3)

boGroup.removeMembers(listOf(caro.walletAddress))
runBlocking { alixGroup.sync() }
assertEquals(alixGroup.memberAddresses().size, 2)
assertEquals(boGroup.memberAddresses().size, 2)

assertThrows(XMTPException::class.java) {
alixGroup.addMembers(listOf(caro.walletAddress))
}
runBlocking { boGroup.sync() }
assertEquals(alixGroup.memberAddresses().size, 2)
assertEquals(boGroup.memberAddresses().size, 2)
}

@Test
Expand Down Expand Up @@ -241,22 +296,25 @@ class GroupTest {
@Test
fun testCanStreamGroupMessages() = kotlinx.coroutines.test.runTest {
val group = boClient.conversations.newGroup(listOf(alix.walletAddress.lowercase()))
alixClient.conversations.syncGroups()
val alixGroup = alixClient.conversations.listGroups().first()
group.streamMessages().test {
group.send("hi")
alixGroup.send("hi")
assertEquals("hi", awaitItem().body)
group.send("hi again")
alixGroup.send("hi again")
assertEquals("hi again", awaitItem().body)
}
}

@Test
fun testCanStreamDecryptedGroupMessages() = kotlinx.coroutines.test.runTest {
val group = boClient.conversations.newGroup(listOf(alix.walletAddress))

alixClient.conversations.syncGroups()
val alixGroup = alixClient.conversations.listGroups().first()
group.streamDecryptedMessages().test {
group.send("hi")
alixGroup.send("hi")
assertEquals("hi", awaitItem().encodedContent.content.toStringUtf8())
group.send("hi again")
alixGroup.send("hi again")
assertEquals("hi again", awaitItem().encodedContent.content.toStringUtf8())
}
}
Expand Down
3 changes: 1 addition & 2 deletions library/src/main/java/org/xmtp/android/library/Client.kt
Original file line number Diff line number Diff line change
Expand Up @@ -566,8 +566,7 @@ class Client() {

fun canMessage(addresses: List<String>): Boolean {
return runBlocking {
libXMTPClient != null && !libXMTPClient!!.canMessage(addresses.map { it })
.contains(false)
libXMTPClient != null && !libXMTPClient!!.canMessage(addresses).contains(false)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import uniffi.xmtpv3.FfiConversationCallback
import uniffi.xmtpv3.FfiConversations
import uniffi.xmtpv3.FfiGroup
import uniffi.xmtpv3.FfiListConversationsOptions
import uniffi.xmtpv3.GroupPermissions
import java.util.Date
import kotlin.time.Duration.Companion.nanoseconds
import kotlin.time.DurationUnit
Expand Down Expand Up @@ -91,7 +92,10 @@ data class Conversations(
)
}

fun newGroup(accountAddresses: List<String>): Group {
fun newGroup(
accountAddresses: List<String>,
permissions: GroupPermissions = GroupPermissions.EVERYONE_IS_ADMIN,
): Group {
if (accountAddresses.isEmpty()) {
throw XMTPException("Cannot start an empty group chat.")
}
Expand All @@ -105,7 +109,7 @@ data class Conversations(
}

val group = runBlocking {
libXMTPConversations?.createGroup(accountAddresses, permissions = null)
libXMTPConversations?.createGroup(accountAddresses, permissions = permissions)
?: throw XMTPException("Client does not support Groups")
}
return Group(client, group)
Expand Down
13 changes: 11 additions & 2 deletions library/src/main/java/org/xmtp/android/library/Group.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import uniffi.xmtpv3.FfiGroup
import uniffi.xmtpv3.FfiListMessagesOptions
import uniffi.xmtpv3.FfiMessage
import uniffi.xmtpv3.FfiMessageCallback
import java.lang.Exception
import java.util.Date
import kotlin.time.Duration.Companion.nanoseconds
import kotlin.time.DurationUnit
Expand Down Expand Up @@ -133,11 +134,19 @@ class Group(val client: Client, private val libXMTPGroup: FfiGroup) {
}

fun addMembers(addresses: List<String>) {
runBlocking { libXMTPGroup.addMembers(addresses) }
try {
runBlocking { libXMTPGroup.addMembers(addresses) }
} catch (e: Exception) {
throw XMTPException("User does not have permissions", e)
}
}

fun removeMembers(addresses: List<String>) {
runBlocking { libXMTPGroup.removeMembers(addresses) }
try {
runBlocking { libXMTPGroup.removeMembers(addresses) }
} catch (e: Exception) {
throw XMTPException("User does not have permissions", e)
}
}

fun memberAddresses(): List<String> {
Expand Down
Loading