Skip to content

Commit

Permalink
feat: add and remove community members by mod/owner
Browse files Browse the repository at this point in the history
  • Loading branch information
Darlington02 committed Feb 8, 2025
1 parent d5476dc commit 483eaf4
Show file tree
Hide file tree
Showing 3 changed files with 270 additions and 1 deletion.
77 changes: 77 additions & 0 deletions src/community/community.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ pub mod CommunityComponent {
.community_member
.read((community_id, profile_caller));

// check user is a community member
let (is_community_member, _) = self.is_community_member(profile_caller, community_id);
assert(is_community_member == true, NOT_COMMUNITY_MEMBER);

Expand Down Expand Up @@ -244,6 +245,82 @@ pub mod CommunityComponent {
self.communities.write(community_id, updated_community);
}

/// @notice adds new community members
/// @param profiles array of addresses to be added as members
/// @param community_id id of community to add members to
fn add_community_members(
ref self: ComponentState<TContractState>,
profiles: Array<ContractAddress>,
community_id: u256
) {
let caller = get_caller_address();
let community = self.communities.read(community_id);
let community_owner = self.community_owner.read(community_id);
let is_community_mod = self.community_mod.read((community_id, caller));

// check caller is mod or owner
assert(is_community_mod == true || community_owner == caller, UNAUTHORIZED);

let length = profiles.len();
let mut index: u32 = 0;

while index < length {
let profile = *profiles[index];

// check user is not already a member and wasn't previously banned
let (is_community_member, _) = self.is_community_member(profile, community_id);
let is_banned = self.get_ban_status(profile, community_id);
assert(is_community_member != true, ALREADY_MEMBER);
assert(is_banned != true, BANNED_MEMBER);

// add user to the community
self._join_community(profile, community.community_nft_address, community_id);

index += 1;
}
}

/// @notice removes community members
/// @param profiles array of addresses to be removed as members
/// @param community_id id of community to add members to
fn remove_community_members(
ref self: ComponentState<TContractState>,
profiles: Array<ContractAddress>,
community_id: u256
) {
let caller = get_caller_address();
let community = self.communities.read(community_id);
let community_owner = self.community_owner.read(community_id);
let is_community_mod = self.community_mod.read((community_id, caller));

// check caller is mod or owner
assert(is_community_mod == true || community_owner == caller, UNAUTHORIZED);

let length = profiles.len();
let mut index: u32 = 0;

while index < length {
let profile = *profiles[index];

// check user is a community member
let (is_community_member, _) = self.is_community_member(profile, community_id);
assert(is_community_member == true, NOT_COMMUNITY_MEMBER);

let community_member_details = self.community_member.read((community_id, profile));

// remove user from the community
self
._leave_community(
profile,
community.community_nft_address,
community_id,
community_member_details.community_token_id
);

index += 1;
}
}

/// @notice adds a new community mod
/// @param community_id id of community to add moderator
/// @param moderator address to be added as moderator
Expand Down
6 changes: 6 additions & 0 deletions src/interfaces/ICommunity.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ pub trait ICommunity<TState> {
fn join_community(ref self: TState, community_id: u256);
fn leave_community(ref self: TState, community_id: u256);
fn set_community_metadata_uri(ref self: TState, community_id: u256, metadata_uri: ByteArray);
fn add_community_members(
ref self: TState, profiles: Array<ContractAddress>, community_id: u256
);
fn remove_community_members(
ref self: TState, profiles: Array<ContractAddress>, community_id: u256
);
fn add_community_mods(ref self: TState, community_id: u256, moderators: Array<ContractAddress>);
fn remove_community_mods(
ref self: TState, community_id: u256, moderators: Array<ContractAddress>
Expand Down
188 changes: 187 additions & 1 deletion tests/test_community.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ fn test_join_community() {

let (is_member, community_member) = community_dispatcher
.is_community_member(USER_ONE.try_into().unwrap(), community_id);

assert(is_member == true, 'joining community failed');
assert(community_member.community_id == community_id, 'invalid community id');
assert(
Expand Down Expand Up @@ -203,7 +204,6 @@ fn test_should_panic_if_a_user_joins_one_community_twice() {
stop_cheat_caller_address(community_contract_address);
}


#[test]
fn test_joining_community_emits_event() {
let (community_contract_address, _) = __setup__();
Expand Down Expand Up @@ -343,6 +343,192 @@ fn test_leave_community_emits_event() {
);
}

#[test]
fn test_add_community_members() {
let (community_contract_address, _) = __setup__();
let community_dispatcher = ICommunityDispatcher {
contract_address: community_contract_address
};

//create the community
start_cheat_caller_address(community_contract_address, USER_ONE.try_into().unwrap());
let community_id = community_dispatcher.create_community(123);

community_dispatcher
.add_community_members(
array![USER_TWO.try_into().unwrap(), USER_THREE.try_into().unwrap()], community_id
);

let (is_member_1, _) = community_dispatcher
.is_community_member(USER_TWO.try_into().unwrap(), community_id);
let (is_member_2, _) = community_dispatcher
.is_community_member(USER_THREE.try_into().unwrap(), community_id);

assert(is_member_1 == true, 'adding members failed');
assert(is_member_2 == true, 'adding members failed');

stop_cheat_caller_address(community_contract_address);
}

#[test]
fn test_add_community_members_by_mod() {
let (community_contract_address, _) = __setup__();
let community_dispatcher = ICommunityDispatcher {
contract_address: community_contract_address
};

//create the community
start_cheat_caller_address(community_contract_address, USER_ONE.try_into().unwrap());
let community_id = community_dispatcher.create_community(123);

// add mod to community first
community_dispatcher.add_community_members(array![USER_FOUR.try_into().unwrap()], community_id);

// make him a mod
community_dispatcher.add_community_mods(community_id, array![USER_FOUR.try_into().unwrap()]);
stop_cheat_caller_address(community_contract_address);

// try to add community members by mod
start_cheat_caller_address(community_contract_address, USER_FOUR.try_into().unwrap());
community_dispatcher
.add_community_members(
array![USER_TWO.try_into().unwrap(), USER_THREE.try_into().unwrap()], community_id
);

let (is_member_1, _) = community_dispatcher
.is_community_member(USER_TWO.try_into().unwrap(), community_id);
let (is_member_2, _) = community_dispatcher
.is_community_member(USER_THREE.try_into().unwrap(), community_id);

assert(is_member_1 == true, 'adding members failed');
assert(is_member_2 == true, 'adding members failed');

stop_cheat_caller_address(community_contract_address);
}

#[test]
#[should_panic(expected: ('coloniz: user unauthorized!',))]
fn test_add_community_members_should_fail_if_caller_is_not_owner_or_mod() {
let (community_contract_address, _) = __setup__();
let community_dispatcher = ICommunityDispatcher {
contract_address: community_contract_address
};

//create the community
start_cheat_caller_address(community_contract_address, USER_ONE.try_into().unwrap());
let community_id = community_dispatcher.create_community(123);

// try to add community members by random user
start_cheat_caller_address(community_contract_address, USER_TWO.try_into().unwrap());
community_dispatcher
.add_community_members(
array![USER_TWO.try_into().unwrap(), USER_THREE.try_into().unwrap()], community_id
);

stop_cheat_caller_address(community_contract_address);
}

#[test]
fn test_remove_community_members() {
let (community_contract_address, _) = __setup__();
let community_dispatcher = ICommunityDispatcher {
contract_address: community_contract_address
};

//create the community
start_cheat_caller_address(community_contract_address, USER_ONE.try_into().unwrap());
let community_id = community_dispatcher.create_community(123);

// add community members
community_dispatcher
.add_community_members(
array![USER_TWO.try_into().unwrap(), USER_THREE.try_into().unwrap()], community_id
);

// remove community member
community_dispatcher
.remove_community_members(
array![USER_TWO.try_into().unwrap(), USER_THREE.try_into().unwrap()], community_id
);

let (is_member_1, _) = community_dispatcher
.is_community_member(USER_TWO.try_into().unwrap(), community_id);
let (is_member_2, _) = community_dispatcher
.is_community_member(USER_THREE.try_into().unwrap(), community_id);

assert(is_member_1 == false, 'removing members failed');
assert(is_member_2 == false, 'removing members failed');

stop_cheat_caller_address(community_contract_address);
}

#[test]
fn test_remove_community_members_by_mod() {
let (community_contract_address, _) = __setup__();
let community_dispatcher = ICommunityDispatcher {
contract_address: community_contract_address
};

//create the community
start_cheat_caller_address(community_contract_address, USER_ONE.try_into().unwrap());
let community_id = community_dispatcher.create_community(123);

// add mod to community first
community_dispatcher.add_community_members(array![USER_FOUR.try_into().unwrap()], community_id);

// make him a mod
community_dispatcher.add_community_mods(community_id, array![USER_FOUR.try_into().unwrap()]);

// add community members first
community_dispatcher
.add_community_members(
array![USER_TWO.try_into().unwrap(), USER_THREE.try_into().unwrap()], community_id
);

stop_cheat_caller_address(community_contract_address);

// try to remove community members by mod
start_cheat_caller_address(community_contract_address, USER_FOUR.try_into().unwrap());
community_dispatcher
.remove_community_members(array![USER_THREE.try_into().unwrap()], community_id);

let (is_member_1, _) = community_dispatcher
.is_community_member(USER_TWO.try_into().unwrap(), community_id);
let (is_member_2, _) = community_dispatcher
.is_community_member(USER_THREE.try_into().unwrap(), community_id);

assert(is_member_1 == true, 'adding members failed');
assert(is_member_2 == false, 'adding members failed');

stop_cheat_caller_address(community_contract_address);
}

#[test]
#[should_panic(expected: ('coloniz: user unauthorized!',))]
fn test_remove_community_members_should_fail_if_caller_is_not_owner_or_mod() {
let (community_contract_address, _) = __setup__();
let community_dispatcher = ICommunityDispatcher {
contract_address: community_contract_address
};

// create the community
start_cheat_caller_address(community_contract_address, USER_ONE.try_into().unwrap());
let community_id = community_dispatcher.create_community(123);

// add community members first
community_dispatcher
.add_community_members(
array![USER_TWO.try_into().unwrap(), USER_THREE.try_into().unwrap()], community_id
);

// try to remove community members by a random user
start_cheat_caller_address(community_contract_address, USER_TWO.try_into().unwrap());
community_dispatcher
.remove_community_members(array![USER_THREE.try_into().unwrap()], community_id);

stop_cheat_caller_address(community_contract_address);
}

#[test]
fn test_set_community_metadata_uri() {
let (community_contract_address, _) = __setup__();
Expand Down

0 comments on commit 483eaf4

Please sign in to comment.