Skip to content

Commit

Permalink
Update node bindings group permissions (#903)
Browse files Browse the repository at this point in the history
  • Loading branch information
rygine authored Jul 15, 2024
1 parent d9ec08e commit eb05ef1
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 61 deletions.
19 changes: 9 additions & 10 deletions bindings_node/src/conversations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,11 @@ use napi::bindgen_prelude::{Error, Result, Uint8Array};
use napi::threadsafe_function::{ErrorStrategy, ThreadsafeFunction, ThreadsafeFunctionCallMode};
use napi::JsFunction;
use napi_derive::napi;
use xmtp_mls::groups::GroupMetadataOptions;
use xmtp_mls::groups::{GroupMetadataOptions, PreconfiguredPolicies};

use crate::messages::NapiMessage;
use crate::{
groups::{GroupPermissions, NapiGroup},
mls_client::RustXmtpClient,
streams::NapiStreamCloser,
};
use crate::permissions::NapiGroupPermissionsOptions;
use crate::{groups::NapiGroup, mls_client::RustXmtpClient, streams::NapiStreamCloser};

#[napi(object)]
pub struct NapiListConversationsOptions {
Expand All @@ -24,7 +21,7 @@ pub struct NapiListConversationsOptions {

#[napi(object)]
pub struct NapiCreateGroupOptions {
pub permissions: Option<GroupPermissions>,
pub permissions: Option<NapiGroupPermissionsOptions>,
pub group_name: Option<String>,
pub group_image_url_square: Option<String>,
pub group_description: Option<String>,
Expand Down Expand Up @@ -70,9 +67,11 @@ impl NapiConversations {
},
};

let group_permissions = options
.permissions
.map(|group_permissions| group_permissions.into());
let group_permissions = match options.permissions {
Some(NapiGroupPermissionsOptions::AllMembers) => Some(PreconfiguredPolicies::AllMembers),
Some(NapiGroupPermissionsOptions::AdminOnly) => Some(PreconfiguredPolicies::AdminsOnly),
_ => None,
};

let convo = self
.inner_client
Expand Down
49 changes: 3 additions & 46 deletions bindings_node/src/groups.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,47 +8,23 @@ use napi::{
use xmtp_cryptography::signature::ed25519_public_key_to_address;
use xmtp_mls::groups::{
group_metadata::{ConversationType, GroupMetadata},
group_permissions::GroupMutablePermissions,
members::PermissionLevel,
MlsGroup, PreconfiguredPolicies, UpdateAdminListType,
MlsGroup, UpdateAdminListType,
};
use xmtp_proto::xmtp::mls::message_contents::EncodedContent;

use crate::{
encoded_content::NapiEncodedContent,
messages::{NapiListMessagesOptions, NapiMessage},
mls_client::RustXmtpClient,
permissions::NapiGroupPermissions,
streams::NapiStreamCloser,
};

use prost::Message;

use napi_derive::napi;

#[napi]
pub enum GroupPermissions {
EveryoneIsAdmin,
GroupCreatorIsAdmin,
}

impl From<PreconfiguredPolicies> for GroupPermissions {
fn from(policy: PreconfiguredPolicies) -> Self {
match policy {
PreconfiguredPolicies::AllMembers => GroupPermissions::EveryoneIsAdmin,
PreconfiguredPolicies::AdminsOnly => GroupPermissions::GroupCreatorIsAdmin,
}
}
}

impl From<GroupPermissions> for PreconfiguredPolicies {
fn from(permissions: GroupPermissions) -> Self {
match permissions {
GroupPermissions::EveryoneIsAdmin => PreconfiguredPolicies::AllMembers,
GroupPermissions::GroupCreatorIsAdmin => PreconfiguredPolicies::AdminsOnly,
}
}
}

#[napi]
pub struct NapiGroupMetadata {
inner: GroupMetadata,
Expand Down Expand Up @@ -86,25 +62,6 @@ pub struct NapiGroupMember {
pub permission_level: NapiPermissionLevel,
}

#[napi]
pub struct NapiGroupPermissions {
inner: GroupMutablePermissions,
}

#[napi]
impl NapiGroupPermissions {
#[napi]
pub fn policy_type(&self) -> Result<GroupPermissions> {
Ok(
self
.inner
.preconfigured_policy()
.map_err(|e| Error::from_reason(format!("{}", e)))?
.into(),
)
}
}

#[derive(Debug)]
#[napi]
pub struct NapiGroup {
Expand Down Expand Up @@ -419,7 +376,7 @@ impl NapiGroup {
.permissions()
.map_err(|e| Error::from_reason(format!("{}", e)))?;

Ok(NapiGroupPermissions { inner: permissions })
Ok(NapiGroupPermissions::new(permissions))
}

#[napi]
Expand Down
1 change: 1 addition & 0 deletions bindings_node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ pub mod encoded_content;
mod groups;
mod messages;
pub mod mls_client;
mod permissions;
mod streams;
172 changes: 172 additions & 0 deletions bindings_node/src/permissions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
use napi::bindgen_prelude::{Error, Result};
use napi_derive::napi;
use xmtp_mls::groups::{
group_mutable_metadata::MetadataField,
group_permissions::{
BasePolicies, GroupMutablePermissions, MembershipPolicies, MetadataBasePolicies,
MetadataPolicies, PermissionsBasePolicies, PermissionsPolicies,
},
intents::{PermissionPolicyOption, PermissionUpdateType},
PreconfiguredPolicies,
};

#[napi]
pub enum NapiGroupPermissionsOptions {
AllMembers,
AdminOnly,
CustomPolicy,
}

#[napi]
pub enum NapiPermissionUpdateType {
AddMember,
RemoveMember,
AddAdmin,
RemoveAdmin,
UpdateMetadata,
}

impl From<&NapiPermissionUpdateType> for PermissionUpdateType {
fn from(update_type: &NapiPermissionUpdateType) -> Self {
match update_type {
NapiPermissionUpdateType::AddMember => PermissionUpdateType::AddMember,
NapiPermissionUpdateType::RemoveMember => PermissionUpdateType::RemoveMember,
NapiPermissionUpdateType::AddAdmin => PermissionUpdateType::AddAdmin,
NapiPermissionUpdateType::RemoveAdmin => PermissionUpdateType::RemoveAdmin,
NapiPermissionUpdateType::UpdateMetadata => PermissionUpdateType::UpdateMetadata,
}
}
}

#[napi]
pub enum NapiPermissionPolicy {
Allow,
Deny,
Admin,
SuperAdmin,
DoesNotExist,
Other,
}

impl TryInto<PermissionPolicyOption> for NapiPermissionPolicy {
type Error = Error;

fn try_into(self) -> Result<PermissionPolicyOption> {
match self {
NapiPermissionPolicy::Allow => Ok(PermissionPolicyOption::Allow),
NapiPermissionPolicy::Deny => Ok(PermissionPolicyOption::Deny),
NapiPermissionPolicy::Admin => Ok(PermissionPolicyOption::AdminOnly),
NapiPermissionPolicy::SuperAdmin => Ok(PermissionPolicyOption::SuperAdminOnly),
_ => Err(Error::from_reason("InvalidPermissionPolicyOption")),
}
}
}

impl From<&MembershipPolicies> for NapiPermissionPolicy {
fn from(policies: &MembershipPolicies) -> Self {
if let MembershipPolicies::Standard(base_policy) = policies {
match base_policy {
BasePolicies::Allow => NapiPermissionPolicy::Allow,
BasePolicies::Deny => NapiPermissionPolicy::Deny,
BasePolicies::AllowSameMember => NapiPermissionPolicy::Other,
BasePolicies::AllowIfAdminOrSuperAdmin => NapiPermissionPolicy::Admin,
BasePolicies::AllowIfSuperAdmin => NapiPermissionPolicy::SuperAdmin,
}
} else {
NapiPermissionPolicy::Other
}
}
}

impl From<&MetadataPolicies> for NapiPermissionPolicy {
fn from(policies: &MetadataPolicies) -> Self {
if let MetadataPolicies::Standard(base_policy) = policies {
match base_policy {
MetadataBasePolicies::Allow => NapiPermissionPolicy::Allow,
MetadataBasePolicies::Deny => NapiPermissionPolicy::Deny,
MetadataBasePolicies::AllowIfActorAdminOrSuperAdmin => NapiPermissionPolicy::Admin,
MetadataBasePolicies::AllowIfActorSuperAdmin => NapiPermissionPolicy::SuperAdmin,
}
} else {
NapiPermissionPolicy::Other
}
}
}

impl From<&PermissionsPolicies> for NapiPermissionPolicy {
fn from(policies: &PermissionsPolicies) -> Self {
if let PermissionsPolicies::Standard(base_policy) = policies {
match base_policy {
PermissionsBasePolicies::Deny => NapiPermissionPolicy::Deny,
PermissionsBasePolicies::AllowIfActorAdminOrSuperAdmin => NapiPermissionPolicy::Admin,
PermissionsBasePolicies::AllowIfActorSuperAdmin => NapiPermissionPolicy::SuperAdmin,
}
} else {
NapiPermissionPolicy::Other
}
}
}

#[napi(object)]
pub struct NapiPermissionPolicySet {
pub add_member_policy: NapiPermissionPolicy,
pub remove_member_policy: NapiPermissionPolicy,
pub add_admin_policy: NapiPermissionPolicy,
pub remove_admin_policy: NapiPermissionPolicy,
pub update_group_name_policy: NapiPermissionPolicy,
pub update_group_description_policy: NapiPermissionPolicy,
pub update_group_image_url_square_policy: NapiPermissionPolicy,
pub update_group_pinned_frame_url_policy: NapiPermissionPolicy,
}

impl From<PreconfiguredPolicies> for NapiGroupPermissionsOptions {
fn from(policy: PreconfiguredPolicies) -> Self {
match policy {
PreconfiguredPolicies::AllMembers => NapiGroupPermissionsOptions::AllMembers,
PreconfiguredPolicies::AdminsOnly => NapiGroupPermissionsOptions::AdminOnly,
}
}
}

#[napi]
pub struct NapiGroupPermissions {
inner: GroupMutablePermissions,
}

#[napi]
impl NapiGroupPermissions {
pub fn new(permissions: GroupMutablePermissions) -> Self {
Self { inner: permissions }
}

#[napi]
pub fn policy_type(&self) -> Result<NapiGroupPermissionsOptions> {
if let Ok(preconfigured_policy) = self.inner.preconfigured_policy() {
Ok(preconfigured_policy.into())
} else {
Ok(NapiGroupPermissionsOptions::CustomPolicy)
}
}

#[napi]
pub fn policy_set(&self) -> Result<NapiPermissionPolicySet> {
let policy_set = &self.inner.policies;
let metadata_policy_map = &policy_set.update_metadata_policy;
let get_policy = |field: &str| {
metadata_policy_map
.get(field)
.map(NapiPermissionPolicy::from)
.unwrap_or(NapiPermissionPolicy::DoesNotExist)
};
Ok(NapiPermissionPolicySet {
add_member_policy: NapiPermissionPolicy::from(&policy_set.add_member_policy),
remove_member_policy: NapiPermissionPolicy::from(&policy_set.remove_member_policy),
add_admin_policy: NapiPermissionPolicy::from(&policy_set.add_admin_policy),
remove_admin_policy: NapiPermissionPolicy::from(&policy_set.remove_admin_policy),
update_group_name_policy: get_policy(MetadataField::GroupName.as_str()),
update_group_description_policy: get_policy(MetadataField::Description.as_str()),
update_group_image_url_square_policy: get_policy(MetadataField::GroupImageUrlSquare.as_str()),
update_group_pinned_frame_url_policy: get_policy(MetadataField::GroupPinnedFrameUrl.as_str()),
})
}
}
30 changes: 25 additions & 5 deletions bindings_node/test/Conversations.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { encode } from 'punycode'
import { describe, expect, it } from 'vitest'
import { AsyncStream } from '@test/AsyncStream'
import {
createRegisteredClient,
createUser,
encodeTextMessage,
} from '@test/helpers'
import { GroupPermissions, NapiGroup, NapiMessage } from '../dist'
import { NapiGroup, NapiGroupPermissionsOptions, NapiMessage } from '../dist'

describe('Conversations', () => {
it('should not have initial conversations', async () => {
Expand All @@ -30,8 +29,18 @@ describe('Conversations', () => {
expect(group.isActive()).toBe(true)
expect(group.groupName()).toBe('')
expect(group.groupPermissions().policyType()).toBe(
GroupPermissions.EveryoneIsAdmin
NapiGroupPermissionsOptions.AllMembers
)
expect(group.groupPermissions().policySet()).toEqual({
addMemberPolicy: 0,
removeMemberPolicy: 2,
addAdminPolicy: 3,
removeAdminPolicy: 3,
updateGroupNamePolicy: 0,
updateGroupDescriptionPolicy: 0,
updateGroupImageUrlSquarePolicy: 0,
updateGroupPinnedFrameUrlPolicy: 0,
})
expect(group.addedByInboxId()).toBe(client1.inboxId())
expect(group.findMessages().length).toBe(1)
const members = group.listMembers()
Expand Down Expand Up @@ -130,15 +139,26 @@ describe('Conversations', () => {
const groupWithPermissions = await client1
.conversations()
.createGroup([user4.account.address], {
permissions: GroupPermissions.GroupCreatorIsAdmin,
permissions: NapiGroupPermissionsOptions.AdminOnly,
})
expect(groupWithPermissions).toBeDefined()
expect(groupWithPermissions.groupName()).toBe('')
expect(groupWithPermissions.groupImageUrlSquare()).toBe('')
expect(groupWithPermissions.groupPermissions().policyType()).toBe(
GroupPermissions.GroupCreatorIsAdmin
NapiGroupPermissionsOptions.AdminOnly
)

expect(groupWithPermissions.groupPermissions().policySet()).toEqual({
addMemberPolicy: 2,
removeMemberPolicy: 2,
addAdminPolicy: 3,
removeAdminPolicy: 3,
updateGroupNamePolicy: 2,
updateGroupDescriptionPolicy: 2,
updateGroupImageUrlSquarePolicy: 2,
updateGroupPinnedFrameUrlPolicy: 2,
})

const groupWithDescription = await client1
.conversations()
.createGroup([user2.account.address], {
Expand Down

0 comments on commit eb05ef1

Please sign in to comment.