Skip to content

Commit

Permalink
feat: added update permissions functions and updated tests
Browse files Browse the repository at this point in the history
  • Loading branch information
cameronvoell committed Jul 2, 2024
1 parent bcfac48 commit f4f45c4
Show file tree
Hide file tree
Showing 8 changed files with 523 additions and 120 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import expo.modules.xmtpreactnativesdk.wrappers.DecryptedLocalAttachment
import expo.modules.xmtpreactnativesdk.wrappers.EncryptedLocalAttachment
import expo.modules.xmtpreactnativesdk.wrappers.GroupWrapper
import expo.modules.xmtpreactnativesdk.wrappers.MemberWrapper
import expo.modules.xmtpreactnativesdk.wrappers.PermissionPolicySetWrapper
import expo.modules.xmtpreactnativesdk.wrappers.PreparedLocalMessage
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope
Expand Down Expand Up @@ -1165,6 +1166,21 @@ class XMTPModule : Module() {
}
}

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

val permissionPolicySet = group?.permissionPolicySet()
if (permissionPolicySet != null) {
PermissionPolicySetWrapper.encodeToJsonString(permissionPolicySet)
} else {
throw XMTPException("Permission policy set not found for group: $id")
}
}
}

AsyncFunction("processGroupMessage") Coroutine { inboxId: String, id: String, encryptedMessage: String ->
withContext(Dispatchers.IO) {
logV("processGroupMessage")
Expand Down
10 changes: 5 additions & 5 deletions example/ios/xmtpreactnativesdkexample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@
LastUpgradeCheck = 1130;
TargetAttributes = {
13B07F861A680F5B00A75B9A = {
DevelopmentTeam = FY4NZR34Z3;
DevelopmentTeam = 65GVVS9K6W;
LastSwiftMigration = 1250;
};
A6A5DB842A00551E001DF8C2 = {
Expand Down Expand Up @@ -408,7 +408,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = xmtpreactnativesdkexample/xmtpreactnativesdkexample.entitlements;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = FY4NZR34Z3;
DEVELOPMENT_TEAM = 65GVVS9K6W;
ENABLE_BITCODE = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
Expand All @@ -424,7 +424,7 @@
"-lc++",
);
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
PRODUCT_BUNDLE_IDENTIFIER = expo.modules.xmtpreactnativesdk.example;
PRODUCT_BUNDLE_IDENTIFIER = cvoell.modules.xmtpreactnativesdk.example;
PRODUCT_NAME = xmtpreactnativesdkexample;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
Expand All @@ -441,7 +441,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = xmtpreactnativesdkexample/xmtpreactnativesdkexample.entitlements;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = FY4NZR34Z3;
DEVELOPMENT_TEAM = 65GVVS9K6W;
INFOPLIST_FILE = xmtpreactnativesdkexample/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
Expand All @@ -452,7 +452,7 @@
"-lc++",
);
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
PRODUCT_BUNDLE_IDENTIFIER = expo.modules.xmtpreactnativesdk.example;
PRODUCT_BUNDLE_IDENTIFIER = cvoell.modules.xmtpreactnativesdk.example;
PRODUCT_NAME = xmtpreactnativesdkexample;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
Expand Down
158 changes: 79 additions & 79 deletions example/ios/xmtpreactnativesdkexample/Info.plist
Original file line number Diff line number Diff line change
@@ -1,82 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>xmtp-react-native-sdk-example</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>expo.modules.xmtpreactnativesdk.example</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
<key>NSCameraUsageDescription</key>
<string>The app accesses your camera to let you attach photos as messages.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to access your microphone</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>The app accesses your photos to let you attach them as messages.</string>
<key>UILaunchStoryboardName</key>
<string>SplashScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIRequiresFullScreen</key>
<false/>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleDefault</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>xmtp-react-native-sdk-example</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>expo.modules.xmtpreactnativesdk.example</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
<key>NSCameraUsageDescription</key>
<string>The app accesses your camera to let you attach photos as messages.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Allow $(PRODUCT_NAME) to access your microphone</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>The app accesses your photos to let you attach them as messages.</string>
<key>UILaunchStoryboardName</key>
<string>SplashScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UIRequiresFullScreen</key>
<false/>
<key>UIStatusBarStyle</key>
<string>UIStatusBarStyleDefault</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>
95 changes: 83 additions & 12 deletions example/src/tests/groupPermissionsTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,8 @@ test('new group has expected admin list and super admin list', async () => {
const superAdminList = await alixGroup.listSuperAdmins()

assert(
adminList.length === 1,
`adminList.length should be 1 but was ${adminList.length}`
)
assert(
adminList[0] === alix.inboxId,
`adminList[0] should be ${alix.address} but was ${adminList[0]}`
adminList.length === 0,
`adminList.length should be 0 but was ${adminList.length}`
)
assert(
superAdminList.length === 1,
Expand Down Expand Up @@ -88,9 +84,9 @@ test('in admin only group, members can not update group name unless they are an
{ permissionLevel: 'admin_only' }
)

if (alixGroup.permissionLevel !== 'admin_only') {
if ((await alixGroup.permissionPolicySet()).addMemberPolicy !== 'admin') {
throw Error(
`Group permission level should be admin_only but was ${alixGroup.permissionLevel}`
`Group add member policy should be admin but was ${(await alixGroup.permissionPolicySet()).addMemberPolicy}`
)
}

Expand Down Expand Up @@ -123,9 +119,11 @@ test('in admin only group, members can update group name once they are an admin'
{ permissionLevel: 'admin_only' }
)

if (alixGroup.permissionLevel !== 'admin_only') {
if (
(await alixGroup.permissionPolicySet()).updateGroupNamePolicy !== 'admin'
) {
throw Error(
`Group permission level should be admin_only but was ${alixGroup.permissionLevel}`
`Group update name policy should be admin but was ${(await alixGroup.permissionPolicySet()).updateGroupNamePolicy}`
)
}

Expand Down Expand Up @@ -174,9 +172,11 @@ test('in admin only group, members can not update group name after admin status
{ permissionLevel: 'admin_only' }
)

if (alixGroup.permissionLevel !== 'admin_only') {
if (
(await alixGroup.permissionPolicySet()).updateGroupNamePolicy !== 'admin'
) {
throw Error(
`Group permission level should be admin_only but was ${alixGroup.permissionLevel}`
`Group update name policy should be admin but was ${(await alixGroup.permissionPolicySet()).updateGroupNamePolicy}`
)
}

Expand Down Expand Up @@ -392,3 +392,74 @@ test('group with All Members policy has remove function that is admin only', asy

return true
})

test('can update group permissions', 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 bo is a super admin
assert(
(await boGroup.isSuperAdmin(bo.inboxId)) === true,
`bo should be a super admin`
)

// Verify that group has the expected group description permission
assert(
(await boGroup.permissionPolicySet()).updateGroupDescriptionPolicy ===
'admin',
`boGroup.permissionPolicySet.updateGroupDescriptionPolicy should be admin but was ${(await boGroup.permissionPolicySet()).updateGroupDescriptionPolicy}`
)

// Verify that Bo can update the group description
await boGroup.updateGroupDescription('new description')
await boGroup.sync()
assert(
(await boGroup.groupDescription()) === 'new description',
`boGroup.groupDescription should be "new description" but was ${boGroup.groupDescription}`
)

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

// Verify that alix can not update permissions
try {
await alixGroup.updateGroupDescriptionPermission('allow')
assert(false, 'Alix should not be able to update the group name permission')
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (error) {
// expected
}

// Verify that bo can update permissions
await boGroup.updateGroupDescriptionPermission('allow')
await boGroup.sync()
assert(
(await boGroup.permissionPolicySet()).updateGroupDescriptionPolicy ===
'allow',
`boGroup.permissionPolicySet.updateGroupDescriptionPolicy should be allow but was ${(await boGroup.permissionPolicySet()).updateGroupDescriptionPolicy}`
)

// Verify that alix can now update the group description
await alixGroup.updateGroupDescription('new description 2')
await alixGroup.sync()
assert(
(await alixGroup.groupDescription()) === 'new description 2',
`alixGroup.groupDescription should be "new description 2" but was ${alixGroup.groupDescription}`
)

return true
})
4 changes: 2 additions & 2 deletions example/src/tests/groupTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1137,9 +1137,9 @@ test('can make a group with admin permissions', async () => {
{ permissionLevel: 'admin_only' }
)

if (group.permissionPolicySet.addMemberPolicy !== 'admin') {
if ((await group.permissionPolicySet()).addMemberPolicy !== 'admin') {
throw Error(
`Group permission level should be admin but was ${group.permissionPolicySet.addMemberPolicy}`
`Group permission level should be admin but was ${(await group.permissionPolicySet()).addMemberPolicy}`
)
}

Expand Down
Loading

0 comments on commit f4f45c4

Please sign in to comment.