Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
43376ab
adding membership module - storage
mnaamani Mar 13, 2019
216e694
use default implicit value for paid terms instead of initializing map
mnaamani Mar 13, 2019
a7d4aac
add migration
mnaamani Mar 14, 2019
6923186
renaming, adding handles map
mnaamani Mar 14, 2019
1237df8
membership: implement buy_membership
mnaamani Mar 14, 2019
918868e
make avatar_uri an Option instead of empty string to represent no uri
mnaamani Mar 14, 2019
cb1a3a7
add simple buy membership method
mnaamani Mar 14, 2019
6e202d9
burn fee when buying membership
mnaamani Mar 14, 2019
54738e7
keep extrinsic validation outside insert_new_paid_member
mnaamani Mar 14, 2019
e99cb53
update methods for profile
mnaamani Mar 14, 2019
6f46ad1
add method to change multiple profile user infos in one transaction
mnaamani Mar 14, 2019
ac0c928
check allowed new members before accepting new members
mnaamani Mar 14, 2019
f095b67
handle runtime uptime by using spec_version
mnaamani Mar 14, 2019
1d63f67
fix batch profile update
mnaamani Mar 14, 2019
7ae24d0
rename update profile method, and don't truncate avatar uri
mnaamani Mar 16, 2019
2d3329a
member sub accounts
mnaamani Mar 16, 2019
da0a072
add some notes on sub-accounts
mnaamani Mar 16, 2019
31fd1de
default min length of handle 5 chars
mnaamani Mar 16, 2019
95e4cd3
adjust avatar, handle and about text default max lengths
mnaamani Mar 16, 2019
478fbe0
reorg membership into a module directory
mnaamani Mar 19, 2019
a227fa3
add tests for membership
mnaamani Mar 19, 2019
27b7841
membership tests
mnaamani Mar 20, 2019
5ba5f86
membership: more tests
mnaamani Mar 20, 2019
74531d2
membership sub accounts, fix updating subaccounts
mnaamani Mar 20, 2019
3328650
membership tests
mnaamani Mar 20, 2019
bf2f5d5
introduce IsActiveMember trait
mnaamani Mar 20, 2019
c8b70cc
use IsActiveMember trait in election and runtime upgrade proposal mod…
mnaamani Mar 20, 2019
c7326e1
factor our migration to its own module
mnaamani Mar 20, 2019
53e54b6
additional comments on membership methods
mnaamani Mar 20, 2019
3fab73d
membership sub accounts - revert (move to staked roles)
mnaamani Mar 21, 2019
9f07751
add member through screener
mnaamani Mar 21, 2019
3e43d9e
refactor membership: renamed registry module to members
mnaamani Mar 25, 2019
75d835d
members: refactor insert members method
mnaamani Mar 25, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ extern crate parity_codec_derive;
pub mod governance;
use governance::{election, council, proposals};
mod memo;
mod membership;

use rstd::prelude::*;
#[cfg(feature = "std")]
Expand Down Expand Up @@ -224,6 +225,13 @@ impl memo::Trait for Runtime {
type Event = Event;
}

impl membership::Trait for Runtime {
type Event = Event;
type MemberId = u64;
type PaidTermId = u32;
type SubscriptionId = u32;
}

construct_runtime!(
pub enum Runtime with Log(InternalLog: DigestItem<Hash, Ed25519AuthorityId>) where
Block = Block,
Expand All @@ -244,6 +252,7 @@ construct_runtime!(
CouncilElection: election::{Module, Call, Storage, Event<T>, Config<T>},
Council: council::{Module, Call, Storage, Event<T>, Config<T>},
Memo: memo::{Module, Call, Storage, Event<T>},
Membership: membership,
}
);

Expand Down
109 changes: 109 additions & 0 deletions src/membership.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#![cfg_attr(not(feature = "std"), no_std)]

use rstd::prelude::*;
use parity_codec::Codec;
use parity_codec_derive::{Encode, Decode};
use srml_support::{StorageMap, dispatch::Result, decl_module, decl_storage, decl_event, ensure, Parameter};
use srml_support::traits::{Currency};
use runtime_primitives::traits::{Zero, SimpleArithmetic, As, Member, MaybeSerializeDebug};
use system::{self, ensure_signed};
use crate::governance::{GovernanceCurrency, BalanceOf };

pub trait Trait: system::Trait + GovernanceCurrency {
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;

type MemberId: Parameter + Member + SimpleArithmetic + Codec + Default + Copy + As<usize> + As<u64> + MaybeSerializeDebug;

type PaidTermId: Parameter + Member + SimpleArithmetic + Codec + Default + Copy + As<usize> + As<u32> + MaybeSerializeDebug;

type SubscriptionId: Parameter + Member + SimpleArithmetic + Codec + Default + Copy + As<usize> + As<u32> + MaybeSerializeDebug;
}

#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[derive(Encode, Decode)]
pub struct Profile<T: Trait> {
id: T::MemberId, // is it necessary to have the id in the struct?
handle: u32,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
handle: u32,
handle: Vec<u8>,

avatarUri: Vec<u8>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Option for a case if a user has not set their avatar.

Suggested change
avatarUri: Vec<u8>,
avatarUri: Option<Vec<u8>>,

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decided on default empty vector == empty string to represent same as not setting avatar or about text. Also makes the batch updating logic simpler.. how to differentiate between user wanting to pass None to 'unset' avatar, or None as in they don't want to update the avatar

Copy link
Contributor

@siman siman Mar 14, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. In such case, it should be Option<Option<Vec<u8>>> and then if you want to set avatar_uri to None you will pass it with UserInfo as Some(None). And if you don't want to update it, then just None.

description: Vec<u8>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest naming this field as about such as description is a better word for items, but not a person

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Option for a case if a user has not set their about - this is not required, yes?

Suggested change
description: Vec<u8>,
about: Option<Vec<u8>>,

added: T::BlockNumber,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
added: T::BlockNumber,
registeredAt: T::BlockNumber,

entry: EntryMethod<T>,
suspended: bool,
subscription: Option<T::SubscriptionId>
}

#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[derive(Encode, Decode)]
pub enum EntryMethod<T: Trait> {
Paid(T::PaidTermId),
Screening(T::AccountId),
}

#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[derive(Encode, Decode)]
pub struct PaidMembershipTerms<T: Trait> {
/// Unique identifier - the term id
id: T::PaidTermId, // is it necessary to have id in the struct?
/// Quantity of native tokens which must be provably burned
fee: BalanceOf<T>,
/// String of capped length describing human readable conditions which are being agreed upon
text: Vec<u8>
}

// Start at 1001? instead to reserve first 1000 ids ?
const FIRST_MEMBER_ID: u64 = 1;
const INITIAL_PAID_TERMS_ID: u64 = 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistency in naming: FIRST_ vs INITIAL_


// TEST: do initial values and build methods get called for store items when the runtime is
// an upgrade? if not we need a differnet way to set them...
decl_storage! {
trait Store for Module<T: Trait> as MembersipRegistry {
FirstMemberId get(first_member_id) : T::MemberId = T::MemberId::sa(FIRST_MEMBER_ID);

/// Id to assign to next member that is added to the registry
NextMemberId get(next_member_id) : T::MemberId = T::MemberId::sa(FIRST_MEMBER_ID);

/// Mapping of member ids to their corresponding accountid
MembersById get(members_by_id) : map T::MemberId => T::AccountId;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
MembersById get(members_by_id) : map T::MemberId => T::AccountId;
AccountIdByMemberId get(account_id_by_member_id) : map T::MemberId => T::AccountId;


/// Mapping of members' accountid to their member id
MemberByAccount get(members_by_account) : map T::AccountId => T::MemberId;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
MemberByAccount get(members_by_account) : map T::AccountId => T::MemberId;
MemberIdByAccountId get(member_id_by_account_id) : map T::AccountId => T::MemberId;


/// Mapping of member's id to their membership profile
// Value is Option<Profile> because it is not meaningful to have a Default value for Profile
MemberProfile get(member_profile_preview) : map T::MemberId => Option<Profile<T>>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is option redundant here? If this map has no member id as a key, then there is no profile for this member id.


/// Next paid membership terms id - 1 reserved for initial terms, (avoid 0 -> default value)
NextPaidMembershipTermsId get(next_paid_membership_terms_id) : T::PaidTermId = T::PaidTermId::sa(2);

/// Paid membership terms record
// Value is an Option because it is not meanigful to have a Default value for a PaidMembershipTerms
// build method should return a vector of tuple(key, value)
// will this method even be called for a runtime upgrade?
PaidMembershipTermsById get(paid_membership_terms_by_id) build(|_| vec![(T::PaidTermId::sa(INITIAL_PAID_TERMS_ID), Some(PaidMembershipTerms {
id: T::PaidTermId::sa(INITIAL_PAID_TERMS_ID),
fee: BalanceOf::<T>::sa(100),
text: String::from("Basic Membership TOS").into_bytes()
}))]) : map T::PaidTermId => Option<PaidMembershipTerms<T>>;

/// Active Paid membership terms
ActivePaidMembershipTerms get(active_paid_membership_terms) : Vec<T::PaidTermId> = vec![T::PaidTermId::sa(INITIAL_PAID_TERMS_ID)];

/// Is the platform is accepting new members or not
PlatformAcceptingNewMemberships get(platform_accepting_new_memberships) : bool = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
PlatformAcceptingNewMemberships get(platform_accepting_new_memberships) : bool = true;
NewMembershipsAllowed get(new_memberships_allowed) : bool = true;

}
}

decl_event! {
pub enum Event<T> where
<T as system::Trait>::AccountId,
<T as Trait>::MemberId {
MemberAdded(MemberId, AccountId),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe rename to MemberRegistered? Registered sounds better when we think about users and social networks

}
}

decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn deposit_event<T>() = default;
}
}