members.rs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. use crate::governance::{BalanceOf, GovernanceCurrency};
  2. use crate::traits::{Members, Roles};
  3. use parity_codec::Codec;
  4. use parity_codec_derive::{Decode, Encode};
  5. use rstd::prelude::*;
  6. use runtime_primitives::traits::{As, MaybeSerializeDebug, Member, SimpleArithmetic};
  7. use srml_support::traits::Currency;
  8. use srml_support::{
  9. decl_event, decl_module, decl_storage, dispatch, ensure, Parameter, StorageMap, StorageValue,
  10. };
  11. use system::{self, ensure_signed};
  12. use timestamp;
  13. pub trait Trait: system::Trait + GovernanceCurrency + timestamp::Trait {
  14. type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
  15. type MemberId: Parameter
  16. + Member
  17. + SimpleArithmetic
  18. + Codec
  19. + Default
  20. + Copy
  21. + As<usize>
  22. + As<u64>
  23. + MaybeSerializeDebug
  24. + PartialEq;
  25. type PaidTermId: Parameter
  26. + Member
  27. + SimpleArithmetic
  28. + Codec
  29. + Default
  30. + Copy
  31. + As<usize>
  32. + As<u64>
  33. + MaybeSerializeDebug
  34. + PartialEq;
  35. type SubscriptionId: Parameter
  36. + Member
  37. + SimpleArithmetic
  38. + Codec
  39. + Default
  40. + Copy
  41. + As<usize>
  42. + As<u64>
  43. + MaybeSerializeDebug
  44. + PartialEq;
  45. type Roles: Roles<Self>;
  46. }
  47. const DEFAULT_FIRST_MEMBER_ID: u64 = 1;
  48. const FIRST_PAID_TERMS_ID: u64 = 1;
  49. // Default paid membership terms
  50. const DEFAULT_PAID_TERM_ID: u64 = 0;
  51. const DEFAULT_PAID_TERM_FEE: u64 = 100; // Can be overidden in genesis config
  52. const DEFAULT_PAID_TERM_TEXT: &str = "Default Paid Term TOS...";
  53. // Default user info constraints
  54. const DEFAULT_MIN_HANDLE_LENGTH: u32 = 5;
  55. const DEFAULT_MAX_HANDLE_LENGTH: u32 = 40;
  56. const DEFAULT_MAX_AVATAR_URI_LENGTH: u32 = 1024;
  57. const DEFAULT_MAX_ABOUT_TEXT_LENGTH: u32 = 2048;
  58. //#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  59. #[derive(Encode, Decode)]
  60. /// Stored information about a registered user
  61. pub struct Profile<T: Trait> {
  62. pub id: T::MemberId,
  63. pub handle: Vec<u8>,
  64. pub avatar_uri: Vec<u8>,
  65. pub about: Vec<u8>,
  66. pub registered_at_block: T::BlockNumber,
  67. pub registered_at_time: T::Moment,
  68. pub entry: EntryMethod<T>,
  69. pub suspended: bool,
  70. pub subscription: Option<T::SubscriptionId>,
  71. }
  72. #[derive(Clone, Debug, Encode, Decode, PartialEq)]
  73. /// Structure used to batch user configurable profile information when registering or updating info
  74. pub struct UserInfo {
  75. pub handle: Option<Vec<u8>>,
  76. pub avatar_uri: Option<Vec<u8>>,
  77. pub about: Option<Vec<u8>>,
  78. }
  79. struct CheckedUserInfo {
  80. handle: Vec<u8>,
  81. avatar_uri: Vec<u8>,
  82. about: Vec<u8>,
  83. }
  84. //#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  85. #[derive(Encode, Decode, Debug, PartialEq)]
  86. pub enum EntryMethod<T: Trait> {
  87. Paid(T::PaidTermId),
  88. Screening(T::AccountId),
  89. }
  90. //#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  91. #[derive(Encode, Decode, Eq, PartialEq)]
  92. pub struct PaidMembershipTerms<T: Trait> {
  93. /// Unique identifier - the term id
  94. pub id: T::PaidTermId,
  95. /// Quantity of native tokens which must be provably burned
  96. pub fee: BalanceOf<T>,
  97. /// String of capped length describing human readable conditions which are being agreed upon
  98. pub text: Vec<u8>,
  99. }
  100. impl<T: Trait> Default for PaidMembershipTerms<T> {
  101. fn default() -> Self {
  102. PaidMembershipTerms {
  103. id: T::PaidTermId::sa(DEFAULT_PAID_TERM_ID),
  104. fee: BalanceOf::<T>::sa(DEFAULT_PAID_TERM_FEE),
  105. text: DEFAULT_PAID_TERM_TEXT.as_bytes().to_vec(),
  106. }
  107. }
  108. }
  109. decl_storage! {
  110. trait Store for Module<T: Trait> as Membership {
  111. /// MemberId's start at this value
  112. pub FirstMemberId get(first_member_id) config(first_member_id): T::MemberId = T::MemberId::sa(DEFAULT_FIRST_MEMBER_ID);
  113. /// MemberId to assign to next member that is added to the registry
  114. pub NextMemberId get(next_member_id) build(|config: &GenesisConfig<T>| config.first_member_id): T::MemberId = T::MemberId::sa(DEFAULT_FIRST_MEMBER_ID);
  115. /// Mapping of member ids to their corresponding primary accountid
  116. pub AccountIdByMemberId get(account_id_by_member_id) : map T::MemberId => T::AccountId;
  117. /// Mapping of members' account ids to their member id.
  118. pub MemberIdByAccountId get(member_id_by_account_id) : map T::AccountId => Option<T::MemberId>;
  119. /// Mapping of member's id to their membership profile
  120. // Value is Option<Profile> because it is not meaningful to have a Default value for Profile
  121. pub MemberProfile get(member_profile) : map T::MemberId => Option<Profile<T>>;
  122. /// Registered unique handles and their mapping to their owner
  123. pub Handles get(handles) : map Vec<u8> => Option<T::MemberId>;
  124. /// Next paid membership terms id
  125. pub NextPaidMembershipTermsId get(next_paid_membership_terms_id) : T::PaidTermId = T::PaidTermId::sa(FIRST_PAID_TERMS_ID);
  126. /// Paid membership terms record
  127. // Remember to add _genesis_phantom_data: std::marker::PhantomData{} to membership
  128. // genesis config if not providing config() or extra_genesis
  129. pub PaidMembershipTermsById get(paid_membership_terms_by_id) build(|config: &GenesisConfig<T>| {
  130. // This method only gets called when initializing storage, and is
  131. // compiled as native code. (Will be called when building `raw` chainspec)
  132. // So it can't be relied upon to initialize storage for runtimes updates.
  133. // Initialization for updated runtime is done in run_migration()
  134. let mut terms: PaidMembershipTerms<T> = Default::default();
  135. terms.fee = config.default_paid_membership_fee;
  136. vec![(terms.id, terms)]
  137. }) : map T::PaidTermId => Option<PaidMembershipTerms<T>>;
  138. /// Active Paid membership terms
  139. pub ActivePaidMembershipTerms get(active_paid_membership_terms) : Vec<T::PaidTermId> = vec![T::PaidTermId::sa(DEFAULT_PAID_TERM_ID)];
  140. /// Is the platform is accepting new members or not
  141. pub NewMembershipsAllowed get(new_memberships_allowed) : bool = true;
  142. pub ScreeningAuthority get(screening_authority) : Option<T::AccountId>;
  143. // User Input Validation parameters - do these really need to be state variables
  144. // I don't see a need to adjust these in future?
  145. pub MinHandleLength get(min_handle_length) : u32 = DEFAULT_MIN_HANDLE_LENGTH;
  146. pub MaxHandleLength get(max_handle_length) : u32 = DEFAULT_MAX_HANDLE_LENGTH;
  147. pub MaxAvatarUriLength get(max_avatar_uri_length) : u32 = DEFAULT_MAX_AVATAR_URI_LENGTH;
  148. pub MaxAboutTextLength get(max_about_text_length) : u32 = DEFAULT_MAX_ABOUT_TEXT_LENGTH;
  149. }
  150. add_extra_genesis {
  151. config(default_paid_membership_fee): BalanceOf<T>;
  152. }
  153. }
  154. decl_event! {
  155. pub enum Event<T> where
  156. <T as system::Trait>::AccountId,
  157. <T as Trait>::MemberId {
  158. MemberRegistered(MemberId, AccountId),
  159. MemberUpdatedAboutText(MemberId),
  160. MemberUpdatedAvatar(MemberId),
  161. MemberUpdatedHandle(MemberId),
  162. }
  163. }
  164. /// Initialization step that runs when the runtime is installed as a runtime upgrade
  165. /// This will and should ONLY be called from the migration module that keeps track of
  166. /// the store version!
  167. impl<T: Trait> Module<T> {
  168. pub fn initialize_storage() {
  169. let default_terms: PaidMembershipTerms<T> = Default::default();
  170. <PaidMembershipTermsById<T>>::insert(default_terms.id, default_terms);
  171. }
  172. }
  173. impl<T: Trait> Members<T> for Module<T> {
  174. type Id = T::MemberId;
  175. fn is_active_member(who: &T::AccountId) -> bool {
  176. match Self::ensure_is_member(who).and_then(|member_id| Self::ensure_profile(member_id)) {
  177. Ok(profile) => !profile.suspended,
  178. Err(_err) => false,
  179. }
  180. }
  181. fn lookup_member_id(who: &T::AccountId) -> Result<Self::Id, &'static str> {
  182. Self::ensure_is_member(who)
  183. }
  184. fn lookup_account_by_member_id(id: Self::Id) -> Result<T::AccountId, &'static str> {
  185. if <AccountIdByMemberId<T>>::exists(&id) {
  186. Ok(Self::account_id_by_member_id(&id))
  187. } else {
  188. Err("member id doesn't exist")
  189. }
  190. }
  191. }
  192. decl_module! {
  193. pub struct Module<T: Trait> for enum Call where origin: T::Origin {
  194. fn deposit_event<T>() = default;
  195. /// Non-members can buy membership
  196. pub fn buy_membership(origin, paid_terms_id: T::PaidTermId, user_info: UserInfo) {
  197. let who = ensure_signed(origin)?;
  198. // make sure we are accepting new memberships
  199. ensure!(Self::new_memberships_allowed(), "new members not allowed");
  200. // ensure key not associated with an existing membership
  201. Self::ensure_not_member(&who)?;
  202. // ensure account is not in a bonded role
  203. ensure!(!T::Roles::is_role_account(&who), "role key cannot be used for membership");
  204. // ensure paid_terms_id is active
  205. let terms = Self::ensure_active_terms_id(paid_terms_id)?;
  206. // ensure enough free balance to cover terms fees
  207. ensure!(T::Currency::can_slash(&who, terms.fee), "not enough balance to buy membership");
  208. let user_info = Self::check_user_registration_info(user_info)?;
  209. // ensure handle is not already registered
  210. Self::ensure_unique_handle(&user_info.handle)?;
  211. let _ = T::Currency::slash(&who, terms.fee);
  212. let member_id = Self::insert_member(&who, &user_info, EntryMethod::Paid(paid_terms_id));
  213. Self::deposit_event(RawEvent::MemberRegistered(member_id, who.clone()));
  214. }
  215. /// Change member's about text
  216. pub fn change_member_about_text(origin, text: Vec<u8>) {
  217. let who = ensure_signed(origin)?;
  218. let member_id = Self::ensure_is_member_primary_account(who.clone())?;
  219. Self::_change_member_about_text(member_id, &text)?;
  220. }
  221. /// Change member's avatar
  222. pub fn change_member_avatar(origin, uri: Vec<u8>) {
  223. let who = ensure_signed(origin)?;
  224. let member_id = Self::ensure_is_member_primary_account(who.clone())?;
  225. Self::_change_member_avatar(member_id, &uri)?;
  226. }
  227. /// Change member's handle. Will ensure new handle is unique and old one will be available
  228. /// for other members to use.
  229. pub fn change_member_handle(origin, handle: Vec<u8>) {
  230. let who = ensure_signed(origin)?;
  231. let member_id = Self::ensure_is_member_primary_account(who.clone())?;
  232. Self::_change_member_handle(member_id, handle)?;
  233. }
  234. /// Update member's all or some of handle, avatar and about text.
  235. pub fn update_profile(origin, user_info: UserInfo) {
  236. let who = ensure_signed(origin)?;
  237. let member_id = Self::ensure_is_member_primary_account(who.clone())?;
  238. if let Some(uri) = user_info.avatar_uri {
  239. Self::_change_member_avatar(member_id, &uri)?;
  240. }
  241. if let Some(about) = user_info.about {
  242. Self::_change_member_about_text(member_id, &about)?;
  243. }
  244. if let Some(handle) = user_info.handle {
  245. Self::_change_member_handle(member_id, handle)?;
  246. }
  247. }
  248. pub fn add_screened_member(origin, new_member: T::AccountId, user_info: UserInfo) {
  249. // ensure sender is screening authority
  250. let sender = ensure_signed(origin)?;
  251. if let Some(screening_authority) = Self::screening_authority() {
  252. ensure!(sender == screening_authority, "not screener");
  253. } else {
  254. // no screening authority defined. Cannot accept this request
  255. return Err("no screening authority defined");
  256. }
  257. // make sure we are accepting new memberships
  258. ensure!(Self::new_memberships_allowed(), "new members not allowed");
  259. // ensure key not associated with an existing membership
  260. Self::ensure_not_member(&new_member)?;
  261. // ensure account is not in a bonded role
  262. ensure!(!T::Roles::is_role_account(&new_member), "role key cannot be used for membership");
  263. let user_info = Self::check_user_registration_info(user_info)?;
  264. // ensure handle is not already registered
  265. Self::ensure_unique_handle(&user_info.handle)?;
  266. let member_id = Self::insert_member(&new_member, &user_info, EntryMethod::Screening(sender));
  267. Self::deposit_event(RawEvent::MemberRegistered(member_id, new_member.clone()));
  268. }
  269. pub fn set_screening_authority(authority: T::AccountId) {
  270. <ScreeningAuthority<T>>::put(authority);
  271. }
  272. }
  273. }
  274. impl<T: Trait> Module<T> {
  275. fn ensure_not_member(who: &T::AccountId) -> dispatch::Result {
  276. ensure!(
  277. !<MemberIdByAccountId<T>>::exists(who),
  278. "account already associated with a membership"
  279. );
  280. Ok(())
  281. }
  282. pub fn ensure_is_member(who: &T::AccountId) -> Result<T::MemberId, &'static str> {
  283. let member_id =
  284. Self::member_id_by_account_id(who).ok_or("no member id found for accountid")?;
  285. Ok(member_id)
  286. }
  287. fn ensure_is_member_primary_account(who: T::AccountId) -> Result<T::MemberId, &'static str> {
  288. let member_id = Self::ensure_is_member(&who)?;
  289. ensure!(
  290. Self::account_id_by_member_id(member_id) == who,
  291. "not primary account"
  292. );
  293. Ok(member_id)
  294. }
  295. fn ensure_profile(id: T::MemberId) -> Result<Profile<T>, &'static str> {
  296. let profile = Self::member_profile(&id).ok_or("member profile not found")?;
  297. Ok(profile)
  298. }
  299. fn ensure_active_terms_id(
  300. terms_id: T::PaidTermId,
  301. ) -> Result<PaidMembershipTerms<T>, &'static str> {
  302. let active_terms = Self::active_paid_membership_terms();
  303. ensure!(
  304. active_terms.iter().any(|&id| id == terms_id),
  305. "paid terms id not active"
  306. );
  307. let terms = Self::paid_membership_terms_by_id(terms_id)
  308. .ok_or("paid membership term id does not exist")?;
  309. Ok(terms)
  310. }
  311. fn ensure_unique_handle(handle: &Vec<u8>) -> dispatch::Result {
  312. ensure!(!<Handles<T>>::exists(handle), "handle already registered");
  313. Ok(())
  314. }
  315. fn validate_handle(handle: &Vec<u8>) -> dispatch::Result {
  316. ensure!(
  317. handle.len() >= Self::min_handle_length() as usize,
  318. "handle too short"
  319. );
  320. ensure!(
  321. handle.len() <= Self::max_handle_length() as usize,
  322. "handle too long"
  323. );
  324. Ok(())
  325. }
  326. fn validate_text(text: &Vec<u8>) -> Vec<u8> {
  327. let mut text = text.clone();
  328. text.truncate(Self::max_about_text_length() as usize);
  329. text
  330. }
  331. fn validate_avatar(uri: &Vec<u8>) -> dispatch::Result {
  332. ensure!(
  333. uri.len() <= Self::max_avatar_uri_length() as usize,
  334. "avatar uri too long"
  335. );
  336. Ok(())
  337. }
  338. /// Basic user input validation
  339. fn check_user_registration_info(user_info: UserInfo) -> Result<CheckedUserInfo, &'static str> {
  340. // Handle is required during registration
  341. let handle = user_info
  342. .handle
  343. .ok_or("handle must be provided during registration")?;
  344. Self::validate_handle(&handle)?;
  345. let about = Self::validate_text(&user_info.about.unwrap_or_default());
  346. let avatar_uri = user_info.avatar_uri.unwrap_or_default();
  347. Self::validate_avatar(&avatar_uri)?;
  348. Ok(CheckedUserInfo {
  349. handle,
  350. avatar_uri,
  351. about,
  352. })
  353. }
  354. // Mutating methods
  355. fn insert_member(
  356. who: &T::AccountId,
  357. user_info: &CheckedUserInfo,
  358. entry_method: EntryMethod<T>,
  359. ) -> T::MemberId {
  360. let new_member_id = Self::next_member_id();
  361. let profile: Profile<T> = Profile {
  362. id: new_member_id,
  363. handle: user_info.handle.clone(),
  364. avatar_uri: user_info.avatar_uri.clone(),
  365. about: user_info.about.clone(),
  366. registered_at_block: <system::Module<T>>::block_number(),
  367. registered_at_time: <timestamp::Module<T>>::now(),
  368. entry: entry_method,
  369. suspended: false,
  370. subscription: None,
  371. };
  372. <MemberIdByAccountId<T>>::insert(who.clone(), new_member_id);
  373. <AccountIdByMemberId<T>>::insert(new_member_id, who.clone());
  374. <MemberProfile<T>>::insert(new_member_id, profile);
  375. <Handles<T>>::insert(user_info.handle.clone(), new_member_id);
  376. <NextMemberId<T>>::mutate(|n| {
  377. *n += T::MemberId::sa(1);
  378. });
  379. new_member_id
  380. }
  381. fn _change_member_about_text(id: T::MemberId, text: &Vec<u8>) -> dispatch::Result {
  382. let mut profile = Self::ensure_profile(id)?;
  383. let text = Self::validate_text(text);
  384. profile.about = text;
  385. Self::deposit_event(RawEvent::MemberUpdatedAboutText(id));
  386. <MemberProfile<T>>::insert(id, profile);
  387. Ok(())
  388. }
  389. fn _change_member_avatar(id: T::MemberId, uri: &Vec<u8>) -> dispatch::Result {
  390. let mut profile = Self::ensure_profile(id)?;
  391. Self::validate_avatar(uri)?;
  392. profile.avatar_uri = uri.clone();
  393. Self::deposit_event(RawEvent::MemberUpdatedAvatar(id));
  394. <MemberProfile<T>>::insert(id, profile);
  395. Ok(())
  396. }
  397. fn _change_member_handle(id: T::MemberId, handle: Vec<u8>) -> dispatch::Result {
  398. let mut profile = Self::ensure_profile(id)?;
  399. Self::validate_handle(&handle)?;
  400. Self::ensure_unique_handle(&handle)?;
  401. <Handles<T>>::remove(&profile.handle);
  402. <Handles<T>>::insert(handle.clone(), id);
  403. profile.handle = handle;
  404. Self::deposit_event(RawEvent::MemberUpdatedHandle(id));
  405. <MemberProfile<T>>::insert(id, profile);
  406. Ok(())
  407. }
  408. }