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

Adding pinned frame metadata field #436

Merged
merged 3 commits into from
Jul 3, 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
6 changes: 3 additions & 3 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ repositories {
dependencies {
implementation project(':expo-modules-core')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${getKotlinVersion()}"
implementation "org.xmtp:android:0.14.2"
implementation "org.xmtp:android:0.14.3"
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'com.facebook.react:react-native:0.71.3'
implementation "com.daveanthonythomas.moshipack:moshipack:1.0.1"
Expand All @@ -108,9 +108,9 @@ dependencies {
// implementation 'io.grpc:grpc-kotlin-stub:1.4.1'
// implementation 'io.grpc:grpc-okhttp:1.62.2'
// implementation 'io.grpc:grpc-protobuf-lite:1.62.2'
// implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3'
// implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0'
// implementation 'org.web3j:crypto:5.0.0'
// implementation "net.java.dev.jna:jna:5.14.0@aar"
// api 'com.google.protobuf:protobuf-kotlin-lite:3.22.3'
// api 'org.xmtp:proto-kotlin:3.61.1'
// api 'org.xmtp:proto-kotlin:3.62.1'
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import expo.modules.xmtpreactnativesdk.wrappers.ConsentWrapper.Companion.consent
import expo.modules.xmtpreactnativesdk.wrappers.ContentJson
import expo.modules.xmtpreactnativesdk.wrappers.ConversationContainerWrapper
import expo.modules.xmtpreactnativesdk.wrappers.ConversationWrapper
import expo.modules.xmtpreactnativesdk.wrappers.CreateGroupParamsWrapper
import expo.modules.xmtpreactnativesdk.wrappers.DecodedMessageWrapper
import expo.modules.xmtpreactnativesdk.wrappers.DecryptedLocalAttachment
import expo.modules.xmtpreactnativesdk.wrappers.EncryptedLocalAttachment
Expand Down Expand Up @@ -834,25 +835,28 @@ class XMTPModule : Module() {
ConversationWrapper.encode(client, conversation)
}
}
AsyncFunction("createGroup") Coroutine { inboxId: String, peerAddresses: List<String>, permission: String, groupName: String, groupImageUrlSquare: String, groupDescription: String ->
AsyncFunction("createGroup") Coroutine { inboxId: String, peerAddresses: List<String>, permission: String, groupOptionsJson: String ->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this improvement 🙌

withContext(Dispatchers.IO) {
logV("createGroup")
val client = clients[inboxId] ?: throw XMTPException("No client")
val permissionLevel = when (permission) {
"admin_only" -> GroupPermissionPreconfiguration.ADMIN_ONLY
else -> GroupPermissionPreconfiguration.ALL_MEMBERS
}
val createGroupParams = CreateGroupParamsWrapper.createGroupParamsFromJson(groupOptionsJson)
val group = client.conversations.newGroup(
peerAddresses,
permissionLevel,
groupName,
groupImageUrlSquare,
groupDescription
createGroupParams.groupName,
createGroupParams.groupImageUrlSquare,
createGroupParams.groupDescription,
createGroupParams.groupPinnedFrameUrl
)
GroupWrapper.encode(client, group)
}
}


AsyncFunction("listMemberInboxIds") Coroutine { inboxId: String, groupId: String ->
withContext(Dispatchers.IO) {
logV("listMembers")
Expand Down Expand Up @@ -988,6 +992,26 @@ class XMTPModule : Module() {
}
}

AsyncFunction("groupPinnedFrameUrl") Coroutine { inboxId: String, id: String ->
withContext(Dispatchers.IO) {
logV("groupPinnedFrameUrl")
val client = clients[inboxId] ?: throw XMTPException("No client")
val group = findGroup(inboxId, id)

group?.pinnedFrameUrl
}
}

AsyncFunction("updateGroupPinnedFrameUrl") Coroutine { inboxId: String, id: String, pinnedFrameUrl: String ->
withContext(Dispatchers.IO) {
logV("updateGroupPinnedFrameUrl")
val client = clients[inboxId] ?: throw XMTPException("No client")
val group = findGroup(inboxId, id)

group?.updateGroupPinnedFrameUrl(pinnedFrameUrl)
}
}

AsyncFunction("isGroupActive") Coroutine { inboxId: String, id: String ->
withContext(Dispatchers.IO) {
logV("isGroupActive")
Expand Down Expand Up @@ -1166,6 +1190,16 @@ class XMTPModule : Module() {
}
}

AsyncFunction("updateGroupPinnedFrameUrlPermission") Coroutine { clientInboxId: String, id: String, newPermission: String ->
withContext(Dispatchers.IO) {
logV("updateGroupPinnedFrameUrlPermission")
val client = clients[clientInboxId] ?: throw XMTPException("No client")
val group = findGroup(clientInboxId, id)

group?.updateGroupPinnedFrameUrlPermission(getPermissionOption(newPermission))
}
}

AsyncFunction("permissionPolicySet") Coroutine { inboxId: String, id: String ->
withContext(Dispatchers.IO) {
logV("groupImageUrlSquare")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package expo.modules.xmtpreactnativesdk.wrappers

import com.google.gson.JsonParser

class CreateGroupParamsWrapper(
val groupName: String,
val groupImageUrlSquare: String,
val groupDescription: String,
val groupPinnedFrameUrl: String,
) {
companion object {
fun createGroupParamsFromJson(authParams: String): CreateGroupParamsWrapper {
val jsonOptions = JsonParser.parseString(authParams).asJsonObject
return CreateGroupParamsWrapper(
if (jsonOptions.has("name")) jsonOptions.get("name").asString else "",
if (jsonOptions.has("imageUrlSquare")) jsonOptions.get("imageUrlSquare").asString else "",
if (jsonOptions.has("description")) jsonOptions.get("description").asString else "",
if (jsonOptions.has("pinnedFrameUrl")) jsonOptions.get("pinnedFrameUrl").asString else "",
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ class GroupWrapper {

companion object {
fun encodeToObj(client: Client, group: Group): Map<String, Any> {
val permissionPolicySet = PermissionPolicySetWrapper.encodeToJsonString(group.permissionPolicySet())
return mapOf(
"clientAddress" to client.address,
"id" to group.id.toHex(),
Expand All @@ -18,10 +17,7 @@ class GroupWrapper {
"version" to "GROUP",
"topic" to group.topic,
"creatorInboxId" to group.creatorInboxId(),
"name" to group.name,
"isActive" to group.isActive(),
"imageUrlSquare" to group.imageUrlSquare,
"description" to group.description
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class PermissionPolicySetWrapper {
"updateGroupNamePolicy" to fromPermissionOption(policySet.updateGroupNamePolicy),
"updateGroupDescriptionPolicy" to fromPermissionOption(policySet.updateGroupDescriptionPolicy),
"updateGroupImagePolicy" to fromPermissionOption(policySet.updateGroupImagePolicy),
"updateGroupPinnedFrameUrlPolicy" to fromPermissionOption(policySet.updateGroupPinnedFrameUrlPolicy),
)
}

Expand Down
14 changes: 7 additions & 7 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ PODS:
- hermes-engine/Pre-built (= 0.71.14)
- hermes-engine/Pre-built (0.71.14)
- libevent (2.1.12)
- LibXMTP (0.5.4-beta1)
- LibXMTP (0.5.4-beta2)
- Logging (1.0.0)
- MessagePacker (0.4.7)
- MMKV (1.3.5):
Expand Down Expand Up @@ -449,16 +449,16 @@ PODS:
- GenericJSON (~> 2.0)
- Logging (~> 1.0.0)
- secp256k1.swift (~> 0.1)
- XMTP (0.13.2):
- XMTP (0.13.3):
- Connect-Swift (= 0.12.0)
- GzipSwift
- LibXMTP (= 0.5.4-beta1)
- LibXMTP (= 0.5.4-beta2)
- web3.swift
- XMTPReactNative (0.1.0):
- ExpoModulesCore
- MessagePacker
- secp256k1.swift
- XMTP (= 0.13.2)
- XMTP (= 0.13.3)
- Yoga (1.14.0)

DEPENDENCIES:
Expand Down Expand Up @@ -711,7 +711,7 @@ SPEC CHECKSUMS:
GzipSwift: 893f3e48e597a1a4f62fafcb6514220fcf8287fa
hermes-engine: d7cc127932c89c53374452d6f93473f1970d8e88
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
LibXMTP: f080197cea545a7daf3bc8476d97efc3b225a8d8
LibXMTP: 16096f324c99d44712ed40876fe25150f694feab
Logging: 9ef4ecb546ad3169398d5a723bc9bea1c46bef26
MessagePacker: ab2fe250e86ea7aedd1a9ee47a37083edd41fd02
MMKV: 506311d0494023c2f7e0b62cc1f31b7370fa3cfb
Expand Down Expand Up @@ -763,8 +763,8 @@ SPEC CHECKSUMS:
secp256k1.swift: a7e7a214f6db6ce5db32cc6b2b45e5c4dd633634
SwiftProtobuf: 407a385e97fd206c4fbe880cc84123989167e0d1
web3.swift: 2263d1e12e121b2c42ffb63a5a7beb1acaf33959
XMTP: 76ac90da19ba43afbde1382d57fbcdbdfe9491d8
XMTPReactNative: d3104af9a1504fb42b16c60888993d1d0516afae
XMTP: ca70dd11d709df02999325663e677fe775623d1e
XMTPReactNative: 1b79a6c8748387062ebcebe2c345f77f4998cae2
Yoga: e71803b4c1fff832ccf9b92541e00f9b873119b9

PODFILE CHECKSUM: 95d6ace79946933ecf80684613842ee553dd76a2
Expand Down
51 changes: 50 additions & 1 deletion example/src/tests/groupPermissionsTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,6 @@ test('can not remove a super admin from a group', async () => {

// 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(
Expand Down Expand Up @@ -463,3 +462,53 @@ test('can update group permissions', async () => {

return true
})

test('can update group pinned frame', async () => {
// Create clients
const [alix, bo, caro] = await createClients(3)

// Bo creates a group with Alix and Caro
const boGroup = await bo.conversations.newGroup(
[alix.address, caro.address],
{ permissionLevel: 'admin_only' }
)

// Verify that alix can not update the group pinned frame
await alix.conversations.syncGroups()
const alixGroup = (await alix.conversations.listGroups())[0]
try {
await alixGroup.updateGroupPinnedFrameUrl('new pinned frame')
assert(false, 'Alix should not be able to update the group pinned frame')
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (error) {
// expected
}

// Verify that bo can update the group pinned frame
await boGroup.updateGroupPinnedFrameUrl('new pinned frame 2')
await boGroup.sync()
assert(
(await boGroup.groupPinnedFrameUrl()) === 'new pinned frame 2',
`boGroup.groupPinnedFrameUrl should be "new pinned frame 2" but was ${boGroup.groupPinnedFrameUrl}`
)

// Verify that bo can update the pinned frame permission
await boGroup.updateGroupPinnedFrameUrlPermission('allow')
await boGroup.sync()
assert(
(await boGroup.permissionPolicySet()).updateGroupPinnedFrameUrlPolicy ===
'allow',
`boGroup.permissionPolicySet.updateGroupPinnedFrameUrlPolicy should be allow but was ${(await boGroup.permissionPolicySet()).updateGroupPinnedFrameUrlPolicy}`
)

// Verify that Alix can now update pinned frames
await alixGroup.updateGroupPinnedFrameUrl('new pinned frame 3')
await alixGroup.sync()
await boGroup.sync()
assert(
(await boGroup.groupPinnedFrameUrl()) === 'new pinned frame 3',
`alixGroup.groupPinnedFrameUrl should be "new pinned frame 3" but was ${boGroup.groupPinnedFrameUrl}`
)

return true
})
25 changes: 25 additions & 0 deletions ios/Wrappers/CreateGroupParamsWrapper.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import Foundation

struct CreateGroupParamsWrapper {
let groupName: String
let groupImageUrlSquare: String
let groupDescription: String
let groupPinnedFrameUrl: String

static func createGroupParamsFromJson(_ authParams: String) -> CreateGroupParamsWrapper {
let data = authParams.data(using: .utf8) ?? Data()
let jsonOptions = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: Any] ?? [:]

let groupName = jsonOptions["name"] as? String ?? ""
let groupImageUrlSquare = jsonOptions["imageUrlSquare"] as? String ?? ""
let groupDescription = jsonOptions["description"] as? String ?? ""
let groupPinnedFrameUrl = jsonOptions["pinnedFrameUrl"] as? String ?? ""

return CreateGroupParamsWrapper(
groupName: groupName,
groupImageUrlSquare: groupImageUrlSquare,
groupDescription: groupDescription,
groupPinnedFrameUrl: groupPinnedFrameUrl
)
}
}
4 changes: 0 additions & 4 deletions ios/Wrappers/GroupWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import XMTP
// Wrapper around XMTP.Group to allow passing these objects back into react native.
struct GroupWrapper {
static func encodeToObj(_ group: XMTP.Group, client: XMTP.Client) throws -> [String: Any] {
let permissionPolicySet = try PermissionPolicySetWrapper.encodeToJsonString(group.permissionPolicySet())
return [
"clientAddress": client.address,
"id": group.id.toHex,
Expand All @@ -20,10 +19,7 @@ struct GroupWrapper {
"version": "GROUP",
"topic": group.topic,
"creatorInboxId": try group.creatorInboxId(),
"name": try group.groupName(),
"isActive": try group.isActive(),
"imageUrlSquare": try group.groupImageUrlSquare(),
"description": try group.groupDescription(),
]
}

Expand Down
3 changes: 2 additions & 1 deletion ios/Wrappers/PermissionPolicySetWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ class PermissionPolicySetWrapper {
"removeAdminPolicy": fromPermissionOption(policySet.removeAdminPolicy),
"updateGroupNamePolicy": fromPermissionOption(policySet.updateGroupNamePolicy),
"updateGroupDescriptionPolicy": fromPermissionOption(policySet.updateGroupDescriptionPolicy),
"updateGroupImagePolicy": fromPermissionOption(policySet.updateGroupImagePolicy)
"updateGroupImagePolicy": fromPermissionOption(policySet.updateGroupImagePolicy),
"updateGroupPinnedFrameUrlPolicy": fromPermissionOption(policySet.updateGroupPinnedFrameUrlPolicy)
]
}

Expand Down
46 changes: 44 additions & 2 deletions ios/XMTPModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -696,7 +696,7 @@ public class XMTPModule: Module {
}
}

AsyncFunction("createGroup") { (inboxId: String, peerAddresses: [String], permission: String, groupName: String, groupImageUrlSquare: String, groupDescription: String) -> String in
AsyncFunction("createGroup") { (inboxId: String, peerAddresses: [String], permission: String, groupOptionsJson: String) -> String in
guard let client = await clientsManager.getClient(key: inboxId) else {
throw Error.noClient
}
Expand All @@ -709,7 +709,15 @@ public class XMTPModule: Module {
}
}()
do {
let group = try await client.conversations.newGroup(with: peerAddresses, permissions: permissionLevel, name: groupName, imageUrlSquare: groupImageUrlSquare, description: groupDescription)
let createGroupParams = CreateGroupParamsWrapper.createGroupParamsFromJson(groupOptionsJson)
let group = try await client.conversations.newGroup(
with: peerAddresses,
permissions: permissionLevel,
name: createGroupParams.groupName,
imageUrlSquare: createGroupParams.groupImageUrlSquare,
description: createGroupParams.groupDescription,
pinnedFrameUrl: createGroupParams.groupPinnedFrameUrl
)
return try GroupWrapper.encode(group, client: client)
} catch {
print("ERRRO!: \(error.localizedDescription)")
Expand Down Expand Up @@ -877,6 +885,30 @@ public class XMTPModule: Module {

try await group.updateGroupDescription(groupDescription: description)
}

AsyncFunction("groupPinnedFrameUrl") { (inboxId: String, id: String) -> String in
guard let client = await clientsManager.getClient(key: inboxId) else {
throw Error.noClient
}

guard let group = try await findGroup(inboxId: inboxId, id: id) else {
throw Error.conversationNotFound("no group found for \(id)")
}

return try group.groupPinnedFrameUrl()
}

AsyncFunction("updateGroupPinnedFrameUrl") { (inboxId: String, id: String, pinnedFrameUrl: String) in
guard let client = await clientsManager.getClient(key: inboxId) else {
throw Error.noClient
}

guard let group = try await findGroup(inboxId: inboxId, id: id) else {
throw Error.conversationNotFound("no group found for \(id)")
}

try await group.updateGroupPinnedFrameUrl(groupPinnedFrameUrl: pinnedFrameUrl)
}

AsyncFunction("isGroupActive") { (inboxId: String, id: String) -> Bool in
guard let client = await clientsManager.getClient(key: inboxId) else {
Expand Down Expand Up @@ -1057,6 +1089,16 @@ public class XMTPModule: Module {
}
try await group.updateGroupDescriptionPermission(newPermissionOption: getPermissionOption(permission: newPermission))
}

AsyncFunction("updateGroupPinnedFrameUrlPermission") { (clientInboxId: String, id: String, newPermission: String) in
guard let client = await clientsManager.getClient(key: clientInboxId) else {
throw Error.noClient
}
guard let group = try await findGroup(inboxId: clientInboxId, id: id) else {
throw Error.conversationNotFound("no group found for \(id)")
}
try await group.updateGroupPinnedFrameUrlPermission(newPermissionOption: getPermissionOption(permission: newPermission))
}

AsyncFunction("permissionPolicySet") { (inboxId: String, id: String) async throws -> String in

Expand Down
Loading
Loading