From 6daa3b35162d000f1efc4eac112d3e82998495af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20Dorado=20Su=C3=A1rez?= Date: Fri, 17 Nov 2023 15:59:48 -0500 Subject: [PATCH] feat(pallet/communities): define/implement promote_member and demote_member --- pallets/communities/src/lib.rs | 28 ++++ pallets/communities/src/tests/membership.rs | 159 +++++++++++++++++++- pallets/communities/src/weights.rs | 66 ++++++-- 3 files changed, 235 insertions(+), 18 deletions(-) diff --git a/pallets/communities/src/lib.rs b/pallets/communities/src/lib.rs index a04814ba..5782bffa 100644 --- a/pallets/communities/src/lib.rs +++ b/pallets/communities/src/lib.rs @@ -463,6 +463,34 @@ pub mod pallet { Ok(()) } + /// Increases the rank of a member in the community + #[pallet::call_index(5)] + pub fn promote_member( + origin: OriginFor, + community_id: T::CommunityId, + who: AccountIdLookupOf, + ) -> DispatchResult { + Self::ensure_origin_privileged(origin, &community_id)?; + Self::ensure_active(&community_id)?; + + let who = <::Lookup as StaticLookup>::lookup(who)?; + Self::do_promote_member(&community_id, &who) + } + + /// Decreases the rank of a member in the community + #[pallet::call_index(6)] + pub fn demote_member( + origin: OriginFor, + community_id: T::CommunityId, + who: AccountIdLookupOf, + ) -> DispatchResult { + Self::ensure_origin_privileged(origin, &community_id)?; + Self::ensure_active(&community_id)?; + + let who = <::Lookup as StaticLookup>::lookup(who)?; + Self::do_demote_member(&community_id, &who) + } + // === Governance === /// diff --git a/pallets/communities/src/tests/membership.rs b/pallets/communities/src/tests/membership.rs index 9e73b29d..cd882563 100644 --- a/pallets/communities/src/tests/membership.rs +++ b/pallets/communities/src/tests/membership.rs @@ -1,12 +1,12 @@ use super::*; +const COMMUNITY_MEMBER_1: u64 = 43; +const COMMUNITY_MEMBER_2: u64 = 44; +const COMMUNITY_NON_MEMBER: u64 = 45; + mod add_member { use super::*; - const COMMUNITY_MEMBER_1: AccountId = 43; - const COMMUNITY_MEMBER_2: AccountId = 44; - const COMMUNITY_NON_MEMBER: AccountId = 45; - #[test] fn fails_when_community_is_not_active() { new_test_ext().execute_with(|| { @@ -97,10 +97,6 @@ mod add_member { mod remove_member { use super::*; - const COMMUNITY_MEMBER_1: u64 = 43; - const COMMUNITY_MEMBER_2: u64 = 44; - const COMMUNITY_NON_MEMBER: u64 = 45; - #[test] fn fails_when_community_is_not_active() { new_test_ext().execute_with(|| { @@ -198,3 +194,150 @@ mod remove_member { }); } } + +mod member_rank { + use super::*; + + fn setup() { + super::setup(); + assert_ok!(Communities::do_force_complete_challenge(&COMMUNITY)); + + assert_ok!(Communities::add_member( + RuntimeOrigin::signed(COMMUNITY_ADMIN), + COMMUNITY, + COMMUNITY_MEMBER_1 + )); + } + + mod promote_member { + use super::*; + + #[test] + fn fails_when_caller_not_a_privleged_origin() { + new_test_ext().execute_with(|| { + setup(); + + assert_noop!( + Communities::promote_member( + RuntimeOrigin::signed(COMMUNITY_MEMBER_1), + COMMUNITY, + COMMUNITY_MEMBER_1 + ), + BadOrigin + ); + }); + } + + #[test] + fn fails_when_not_a_community_member() { + new_test_ext().execute_with(|| { + setup(); + + assert_noop!( + Communities::promote_member( + RuntimeOrigin::signed(COMMUNITY_ADMIN), + COMMUNITY, + COMMUNITY_NON_MEMBER + ), + Error::NotAMember, + ); + }); + } + + #[test] + fn it_works() { + new_test_ext().execute_with(|| { + setup(); + + assert_ok!(Communities::promote_member( + RuntimeOrigin::signed(COMMUNITY_ADMIN), + COMMUNITY, + COMMUNITY_MEMBER_1 + )); + assert_eq!(Communities::member_rank(COMMUNITY, COMMUNITY_MEMBER_1), Some(1)); + }); + } + + #[test] + fn should_fail_when_exceeding_rank_upper_bound() { + new_test_ext().execute_with(|| { + setup(); + + while Communities::member_rank(COMMUNITY, COMMUNITY_MEMBER_1) < Some(u8::MAX) { + assert_ok!(Communities::promote_member( + RuntimeOrigin::signed(COMMUNITY_ADMIN), + COMMUNITY, + COMMUNITY_MEMBER_1 + )); + } + + assert_noop!( + Communities::promote_member(RuntimeOrigin::signed(COMMUNITY_ADMIN), COMMUNITY, COMMUNITY_MEMBER_1), + Error::ExceededPromoteBound, + ); + }); + } + } + + mod demote_member { + use crate::MemberRanks; + + use super::*; + + #[test] + fn fails_when_caller_not_a_privleged_origin() { + new_test_ext().execute_with(|| { + setup(); + + assert_noop!( + Communities::demote_member( + RuntimeOrigin::signed(COMMUNITY_MEMBER_1), + COMMUNITY, + COMMUNITY_MEMBER_1 + ), + BadOrigin + ); + }); + } + + #[test] + fn fails_when_not_a_community_member() { + new_test_ext().execute_with(|| { + setup(); + + assert_noop!( + Communities::demote_member(RuntimeOrigin::signed(COMMUNITY_ADMIN), COMMUNITY, COMMUNITY_NON_MEMBER), + Error::NotAMember, + ); + }); + } + + #[test] + fn it_works() { + new_test_ext().execute_with(|| { + setup(); + + MemberRanks::::set(COMMUNITY, COMMUNITY_MEMBER_1, Some(2)); + + assert_ok!(Communities::demote_member( + RuntimeOrigin::signed(COMMUNITY_ADMIN), + COMMUNITY, + COMMUNITY_MEMBER_1 + )); + assert_eq!(Communities::member_rank(COMMUNITY, COMMUNITY_MEMBER_1), Some(1)); + }); + } + + #[test] + fn should_fail_when_exceeding_rank_upper_bound() { + new_test_ext().execute_with(|| { + setup(); + + assert_noop!( + Communities::demote_member(RuntimeOrigin::signed(COMMUNITY_ADMIN), COMMUNITY, COMMUNITY_MEMBER_1), + Error::ExceededDemoteBound, + ); + }); + } + } +} diff --git a/pallets/communities/src/weights.rs b/pallets/communities/src/weights.rs index 38e7ba34..169f3f2f 100644 --- a/pallets/communities/src/weights.rs +++ b/pallets/communities/src/weights.rs @@ -37,6 +37,8 @@ pub trait WeightInfo { fn apply_for() -> Weight; fn set_metadata() -> Weight; fn add_member() -> Weight; + fn promote_member() -> Weight; + fn demote_member() -> Weight; fn remove_member() -> Weight; fn vote() -> Weight; } @@ -87,17 +89,39 @@ impl WeightInfo for SubstrateWeight { Weight::from_parts(9_000_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + + /// Storage: Communities Something (r:0 w:1) + /// Proof: Communities Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn promote_member() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(9_000_000, 0) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } - /// Storage: Communities Something (r:0 w:1) - /// Proof: Communities Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn vote() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_000_000 picoseconds. - Weight::from_parts(9_000_000, 0) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } + /// Storage: Communities Something (r:0 w:1) + /// Proof: Communities Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn demote_member() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(9_000_000, 0) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + + /// Storage: Communities Something (r:0 w:1) + /// Proof: Communities Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn vote() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(9_000_000, 0) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } } // For backwards compatibility and tests @@ -145,6 +169,28 @@ impl WeightInfo for () { Weight::from_parts(9_000_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + + /// Storage: Communities Something (r:0 w:1) + /// Proof: Communities Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn promote_member() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(9_000_000, 0) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } + + /// Storage: Communities Something (r:0 w:1) + /// Proof: Communities Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) + fn demote_member() -> Weight { + // Proof Size summary in bytes: + // Measured: `0` + // Estimated: `0` + // Minimum execution time: 8_000_000 picoseconds. + Weight::from_parts(9_000_000, 0) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } /// Storage: Communities Something (r:0 w:1) /// Proof: Communities Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen)