Skip to content

Commit

Permalink
Latest libxmtp - permissions and description field updates (#360)
Browse files Browse the repository at this point in the history
* update libxmtp-swift references

* Updated for latest bindings, fixed tests

* Add group description functions

* Added funcitons for updating permissions and update permission test

---------

Co-authored-by: cameronvoell <[email protected]>
  • Loading branch information
cameronvoell and cameronvoell authored Jul 2, 2024
1 parent f466b45 commit 77735dc
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 36 deletions.
6 changes: 3 additions & 3 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@
{
"identity" : "libxmtp-swift",
"kind" : "remoteSourceControl",
"location" : "https://github.com/xmtp/libxmtp-swift",
"location" : "https://github.com/xmtp/libxmtp-swift.git",
"state" : {
"revision" : "957945a1886bce6e290a7e763866d80ec6ba475b",
"version" : "0.5.3-beta2"
"revision" : "577a61e568cb5aaff10486172b1ef055faeff5b9",
"version" : "0.5.4-beta1"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ let package = Package(
.package(url: "https://github.com/1024jp/GzipSwift", from: "5.2.0"),
.package(url: "https://github.com/bufbuild/connect-swift", exact: "0.12.0"),
.package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.0.0"),
.package(url: "https://github.com/xmtp/libxmtp-swift.git", branch: "main"),
.package(url: "https://github.com/xmtp/libxmtp-swift.git", exact: "0.5.4-beta1"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
Expand Down
10 changes: 6 additions & 4 deletions Sources/XMTPiOS/Conversations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,10 @@ public actor Conversations {
}

public func newGroup(with addresses: [String],
permissions: GroupPermissions = .allMembers,
permissions: GroupPermissionPreconfiguration = .allMembers,
name: String = "",
imageUrlSquare: String = ""
imageUrlSquare: String = "",
description: String = ""
) async throws -> Group {
guard let v3Client = client.v3Client else {
throw GroupError.alphaMLSNotEnabled
Expand Down Expand Up @@ -175,9 +176,10 @@ public actor Conversations {
throw GroupError.memberNotRegistered(erroredAddresses)
}
let group = try await v3Client.conversations().createGroup(accountAddresses: addresses,
opts: FfiCreateGroupOptions(permissions: permissions,
opts: FfiCreateGroupOptions(permissions: GroupPermissionPreconfiguration.toFfiGroupPermissionOptions(option: permissions),
groupName: name,
groupImageUrlSquare: imageUrlSquare
groupImageUrlSquare: imageUrlSquare,
groupDescription: description
)).fromFFI(client: client)
try await client.contacts.allowGroups(groupIds: [group.id])
return group
Expand Down
41 changes: 39 additions & 2 deletions Sources/XMTPiOS/Group.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ public struct Group: Identifiable, Equatable, Hashable {
try ffiGroup.superAdminList()
}

public func permissionLevel() throws -> GroupPermissions {
return try permissions().policyType()
public func permissionPolicySet() throws -> PermissionPolicySet {
return PermissionPolicySet(ffiPermissionPolicySet: try permissions().policySet())
}

public func creatorInboxId() throws -> String {
Expand Down Expand Up @@ -157,13 +157,50 @@ public struct Group: Identifiable, Equatable, Hashable {
return try ffiGroup.groupImageUrlSquare()
}

public func groupDescription() throws -> String {
return try ffiGroup.groupDescription()
}

public func updateGroupName(groupName: String) async throws {
try await ffiGroup.updateGroupName(groupName: groupName)
}

public func updateGroupImageUrlSquare(imageUrlSquare: String) async throws {
try await ffiGroup.updateGroupImageUrlSquare(groupImageUrlSquare: imageUrlSquare)
}

public func updateGroupDescription(groupDescription: String) async throws {
try await ffiGroup.updateGroupDescription(groupDescription: groupDescription)
}

public func updateAddMemberPermission(newPermissionOption: PermissionOption) async throws {
try await ffiGroup.updatePermissionPolicy(permissionUpdateType: FfiPermissionUpdateType.addMember, permissionPolicyOption: PermissionOption.toFfiPermissionPolicy(option: newPermissionOption), metadataField: nil)
}

public func updateRemoveMemberPermission(newPermissionOption: PermissionOption) async throws {
try await ffiGroup.updatePermissionPolicy(permissionUpdateType: FfiPermissionUpdateType.removeMember, permissionPolicyOption: PermissionOption.toFfiPermissionPolicy(option: newPermissionOption), metadataField: nil)
}

public func updateAddAdminPermission(newPermissionOption: PermissionOption) async throws {
try await ffiGroup.updatePermissionPolicy(permissionUpdateType: FfiPermissionUpdateType.addAdmin, permissionPolicyOption: PermissionOption.toFfiPermissionPolicy(option: newPermissionOption), metadataField: nil)
}

public func updateRemoveAdminPermission(newPermissionOption: PermissionOption) async throws {
try await ffiGroup.updatePermissionPolicy(permissionUpdateType: FfiPermissionUpdateType.removeAdmin, permissionPolicyOption: PermissionOption.toFfiPermissionPolicy(option: newPermissionOption), metadataField: nil)
}

public func updateGroupNamePermission(newPermissionOption: PermissionOption) async throws {
try await ffiGroup.updatePermissionPolicy(permissionUpdateType: FfiPermissionUpdateType.updateMetadata, permissionPolicyOption: PermissionOption.toFfiPermissionPolicy(option: newPermissionOption), metadataField: FfiMetadataField.groupName)
}

public func updateGroupDescriptionPermission(newPermissionOption: PermissionOption) async throws {
try await ffiGroup.updatePermissionPolicy(permissionUpdateType: FfiPermissionUpdateType.updateMetadata, permissionPolicyOption: PermissionOption.toFfiPermissionPolicy(option: newPermissionOption), metadataField: FfiMetadataField.description)
}

public func updateGroupImageUrlSquarePermission(newPermissionOption: PermissionOption) async throws {
try await ffiGroup.updatePermissionPolicy(permissionUpdateType: FfiPermissionUpdateType.updateMetadata, permissionPolicyOption: PermissionOption.toFfiPermissionPolicy(option: newPermissionOption), metadataField: FfiMetadataField.imageUrlSquare)
}


public func processMessage(envelopeBytes: Data) async throws -> DecodedMessage {
let message = try await ffiGroup.processStreamedGroupMessage(envelopeBytes: envelopeBytes)
Expand Down
90 changes: 90 additions & 0 deletions Sources/XMTPiOS/Mls/PermissionPolicySet.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import Foundation
import LibXMTP

public enum PermissionOption {
case allow
case deny
case admin
case superAdmin
case unknown

static func toFfiPermissionPolicy(option: PermissionOption) -> FfiPermissionPolicy {
switch option {
case .allow:
return .allow
case .deny:
return .deny
case .admin:
return .admin
case .superAdmin:
return .superAdmin
case .unknown:
return .other
}
}

static func fromFfiPermissionPolicy(ffiPolicy: FfiPermissionPolicy) -> PermissionOption {
switch ffiPolicy {
case .allow:
return .allow
case .deny:
return .deny
case .admin:
return .admin
case .superAdmin:
return .superAdmin
case .doesNotExist, .other:
return .unknown
}
}
}

public enum GroupPermissionPreconfiguration {
case allMembers
case adminOnly

static func toFfiGroupPermissionOptions(option: GroupPermissionPreconfiguration) -> FfiGroupPermissionsOptions {
switch option {
case .allMembers:
return .allMembers
case .adminOnly:
return .adminOnly
}
}
}

public class PermissionPolicySet {
let ffiPermissionPolicySet: FfiPermissionPolicySet

init(ffiPermissionPolicySet: FfiPermissionPolicySet) {
self.ffiPermissionPolicySet = ffiPermissionPolicySet
}

var addMemberPolicy: PermissionOption {
return PermissionOption.fromFfiPermissionPolicy(ffiPolicy: ffiPermissionPolicySet.addMemberPolicy)
}

var removeMemberPolicy: PermissionOption {
return PermissionOption.fromFfiPermissionPolicy(ffiPolicy: ffiPermissionPolicySet.removeMemberPolicy)
}

var addAdminPolicy: PermissionOption {
return PermissionOption.fromFfiPermissionPolicy(ffiPolicy: ffiPermissionPolicySet.addAdminPolicy)
}

var removeAdminPolicy: PermissionOption {
return PermissionOption.fromFfiPermissionPolicy(ffiPolicy: ffiPermissionPolicySet.removeAdminPolicy)
}

var updateGroupNamePolicy: PermissionOption {
return PermissionOption.fromFfiPermissionPolicy(ffiPolicy: ffiPermissionPolicySet.updateGroupNamePolicy)
}

var updateGroupDescriptionPolicy: PermissionOption {
return PermissionOption.fromFfiPermissionPolicy(ffiPolicy: ffiPermissionPolicySet.updateGroupDescriptionPolicy)
}

var updateGroupImagePolicy: PermissionOption {
return PermissionOption.fromFfiPermissionPolicy(ffiPolicy: ffiPermissionPolicySet.updateGroupImageUrlSquarePolicy)
}
}
49 changes: 41 additions & 8 deletions Tests/XMTPTests/GroupPermissionsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class GroupPermissionTests: XCTestCase {
try await fixtures.aliceClient.conversations.sync()
let aliceGroup = try await fixtures.aliceClient.conversations.groups().first!

XCTAssertTrue(try bobGroup.isAdmin(inboxId: fixtures.bobClient.inboxID))
XCTAssertFalse(try bobGroup.isAdmin(inboxId: fixtures.bobClient.inboxID))
XCTAssertTrue(try bobGroup.isSuperAdmin(inboxId: fixtures.bobClient.inboxID))
XCTAssertFalse(try aliceGroup.isCreator())
XCTAssertFalse(try aliceGroup.isAdmin(inboxId: fixtures.aliceClient.inboxID))
Expand All @@ -81,8 +81,8 @@ class GroupPermissionTests: XCTestCase {
let adminList = try bobGroup.listAdmins()
let superAdminList = try bobGroup.listSuperAdmins()

XCTAssertEqual(adminList.count, 1)
XCTAssertTrue(adminList.contains(fixtures.bobClient.inboxID))
XCTAssertEqual(adminList.count, 0)
XCTAssertFalse(adminList.contains(fixtures.bobClient.inboxID))
XCTAssertEqual(superAdminList.count, 1)
XCTAssertTrue(superAdminList.contains(fixtures.bobClient.inboxID))
}
Expand All @@ -93,16 +93,16 @@ class GroupPermissionTests: XCTestCase {
try await fixtures.aliceClient.conversations.sync()
let aliceGroup = try await fixtures.aliceClient.conversations.groups().first!

XCTAssertTrue(try bobGroup.isAdmin(inboxId: fixtures.bobClient.inboxID))
XCTAssertFalse(try bobGroup.isAdmin(inboxId: fixtures.bobClient.inboxID))
XCTAssertTrue(try bobGroup.isSuperAdmin(inboxId: fixtures.bobClient.inboxID))
XCTAssertFalse(try aliceGroup.isCreator())
XCTAssertFalse(try aliceGroup.isAdmin(inboxId: fixtures.aliceClient.inboxID))
XCTAssertFalse(try aliceGroup.isSuperAdmin(inboxId: fixtures.aliceClient.inboxID))

var adminList = try bobGroup.listAdmins()
var superAdminList = try bobGroup.listSuperAdmins()
XCTAssertEqual(adminList.count, 1)
XCTAssertTrue(adminList.contains(fixtures.bobClient.inboxID))
XCTAssertEqual(adminList.count, 0)
XCTAssertFalse(adminList.contains(fixtures.bobClient.inboxID))
XCTAssertEqual(superAdminList.count, 1)
XCTAssertTrue(superAdminList.contains(fixtures.bobClient.inboxID))

Expand All @@ -125,7 +125,7 @@ class GroupPermissionTests: XCTestCase {
superAdminList = try bobGroup.listSuperAdmins()

XCTAssertTrue(try aliceGroup.isAdmin(inboxId: fixtures.aliceClient.inboxID))
XCTAssertEqual(adminList.count, 2)
XCTAssertEqual(adminList.count, 1)
XCTAssertTrue(adminList.contains(fixtures.aliceClient.inboxID))
XCTAssertEqual(superAdminList.count, 1)

Expand All @@ -144,7 +144,7 @@ class GroupPermissionTests: XCTestCase {
superAdminList = try bobGroup.listSuperAdmins()

XCTAssertFalse(try aliceGroup.isAdmin(inboxId: fixtures.aliceClient.inboxID))
XCTAssertEqual(adminList.count, 1)
XCTAssertEqual(adminList.count, 0)
XCTAssertFalse(adminList.contains(fixtures.aliceClient.inboxID))
XCTAssertEqual(superAdminList.count, 1)

Expand Down Expand Up @@ -254,4 +254,37 @@ class GroupPermissionTests: XCTestCase {
XCTAssertEqual(try bobGroup.groupName(), "Alice group name")
XCTAssertEqual(try aliceGroup.groupName(), "Alice group name")
}

func testCanUpdatePermissions() async throws {
let fixtures = try await localFixtures()
let bobGroup = try await fixtures.bobClient.conversations.newGroup(
with: [fixtures.alice.walletAddress, fixtures.caro.walletAddress],
permissions: .adminOnly
)
try await fixtures.aliceClient.conversations.sync()
let aliceGroup = try await fixtures.aliceClient.conversations.groups().first!

// Verify that Alice cannot update group description
XCTAssertEqual(try bobGroup.groupDescription(), "")
await assertThrowsAsyncError(
try await aliceGroup.updateGroupDescription(groupDescription: "new group description")
)

try await aliceGroup.sync()
try await bobGroup.sync()
XCTAssertEqual(try bobGroup.permissionPolicySet().updateGroupDescriptionPolicy, .admin)

// Update group description permissions so Alice can update
try await bobGroup.updateGroupDescriptionPermission(newPermissionOption: .allow)
try await bobGroup.sync()
try await aliceGroup.sync()
XCTAssertEqual(try bobGroup.permissionPolicySet().updateGroupDescriptionPolicy, .allow)

// Verify that Alice can now update group description
try await aliceGroup.updateGroupDescription(groupDescription: "Alice group description")
try await aliceGroup.sync()
try await bobGroup.sync()
XCTAssertEqual(try bobGroup.groupDescription(), "Alice group description")
XCTAssertEqual(try aliceGroup.groupDescription(), "Alice group description")
}
}
32 changes: 16 additions & 16 deletions Tests/XMTPTests/GroupTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -118,19 +118,19 @@ class GroupTests: XCTestCase {
XCTAssertEqual(try aliceGroup.members.count, 3)
XCTAssertEqual(try bobGroup.members.count, 3)

XCTAssertEqual(try bobGroup.permissionLevel(), .allMembers)
XCTAssertEqual(try aliceGroup.permissionLevel(), .allMembers)
XCTAssertEqual(try bobGroup.permissionPolicySet().addMemberPolicy, .allow)
XCTAssertEqual(try aliceGroup.permissionPolicySet().addMemberPolicy, .allow)

XCTAssert(try bobGroup.isAdmin(inboxId: fixtures.bobClient.inboxID))
XCTAssert(try !bobGroup.isAdmin(inboxId: fixtures.aliceClient.inboxID))
XCTAssert(try aliceGroup.isAdmin(inboxId: fixtures.bobClient.inboxID))
XCTAssert(try !aliceGroup.isAdmin(inboxId: fixtures.aliceClient.inboxID))
XCTAssert(try bobGroup.isSuperAdmin(inboxId: fixtures.bobClient.inboxID))
XCTAssert(try !bobGroup.isSuperAdmin(inboxId: fixtures.aliceClient.inboxID))
XCTAssert(try aliceGroup.isSuperAdmin(inboxId: fixtures.bobClient.inboxID))
XCTAssert(try !aliceGroup.isSuperAdmin(inboxId: fixtures.aliceClient.inboxID))

}

func testCanCreateAGroupWithAdminPermissions() async throws {
let fixtures = try await localFixtures()
let bobGroup = try await fixtures.bobClient.conversations.newGroup(with: [fixtures.alice.address], permissions: GroupPermissions.adminOnly)
let bobGroup = try await fixtures.bobClient.conversations.newGroup(with: [fixtures.alice.address], permissions: GroupPermissionPreconfiguration.adminOnly)
try await fixtures.aliceClient.conversations.sync()
let aliceGroup = try await fixtures.aliceClient.conversations.groups().first!
XCTAssert(!bobGroup.id.isEmpty)
Expand Down Expand Up @@ -170,12 +170,12 @@ class GroupTests: XCTestCase {
XCTAssertEqual(try aliceGroup.members.count, 2)
XCTAssertEqual(try bobGroup.members.count, 2)

XCTAssertEqual(try bobGroup.permissionLevel(), .adminOnly)
XCTAssertEqual(try aliceGroup.permissionLevel(), .adminOnly)
XCTAssert(try bobGroup.isAdmin(inboxId: fixtures.bobClient.inboxID))
XCTAssert(try !bobGroup.isAdmin(inboxId: fixtures.aliceClient.inboxID))
XCTAssert(try aliceGroup.isAdmin(inboxId: fixtures.bobClient.inboxID))
XCTAssert(try !aliceGroup.isAdmin(inboxId: fixtures.aliceClient.inboxID))
XCTAssertEqual(try bobGroup.permissionPolicySet().addMemberPolicy, .admin)
XCTAssertEqual(try aliceGroup.permissionPolicySet().addMemberPolicy, .admin)
XCTAssert(try bobGroup.isSuperAdmin(inboxId: fixtures.bobClient.inboxID))
XCTAssert(try !bobGroup.isSuperAdmin(inboxId: fixtures.aliceClient.inboxID))
XCTAssert(try aliceGroup.isSuperAdmin(inboxId: fixtures.bobClient.inboxID))
XCTAssert(try !aliceGroup.isSuperAdmin(inboxId: fixtures.aliceClient.inboxID))
}

func testCanListGroups() async throws {
Expand Down Expand Up @@ -481,9 +481,9 @@ class GroupTests: XCTestCase {
let bobGroup = try await fixtures.bobClient.conversations.groups()[0]
try await bobGroup.sync()

var bobMessagesCount = try await bobGroup.messages().count
var bobMessagesUnpublishedCount = try await bobGroup.messages(deliveryStatus: .unpublished).count
var bobMessagesPublishedCount = try await bobGroup.messages(deliveryStatus: .published).count
let bobMessagesCount = try await bobGroup.messages().count
let bobMessagesUnpublishedCount = try await bobGroup.messages(deliveryStatus: .unpublished).count
let bobMessagesPublishedCount = try await bobGroup.messages(deliveryStatus: .published).count
XCTAssertEqual(2, bobMessagesCount)
XCTAssertEqual(0, bobMessagesUnpublishedCount)
XCTAssertEqual(2, bobMessagesPublishedCount)
Expand Down
4 changes: 2 additions & 2 deletions XMTP.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Pod::Spec.new do |spec|
#

spec.name = "XMTP"
spec.version = "0.13.0"
spec.version = "0.13.1"
spec.summary = "XMTP SDK Cocoapod"

# This description is used to generate tags and improve search results.
Expand Down Expand Up @@ -44,5 +44,5 @@ Pod::Spec.new do |spec|
spec.dependency "web3.swift"
spec.dependency "GzipSwift"
spec.dependency "Connect-Swift", "= 0.12.0"
spec.dependency 'LibXMTP', '= 0.5.4-beta0'
spec.dependency 'LibXMTP', '= 0.5.4-beta1'
end

0 comments on commit 77735dc

Please sign in to comment.