lib.rs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. // Ensure we're `no_std` when compiling for Wasm.
  2. #![cfg_attr(not(feature = "std"), no_std)]
  3. #![recursion_limit = "256"]
  4. // #[cfg(test)]
  5. // mod tests;
  6. mod errors;
  7. mod permissions;
  8. pub use errors::*;
  9. pub use permissions::*;
  10. use core::hash::Hash;
  11. use codec::Codec;
  12. use codec::{Decode, Encode};
  13. // use frame_support::storage::IterableStorageMap;
  14. use frame_support::{
  15. decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure, traits::Get, Parameter,
  16. };
  17. #[cfg(feature = "std")]
  18. pub use serde::{Deserialize, Serialize};
  19. use sp_arithmetic::traits::{BaseArithmetic, One, Zero};
  20. use sp_runtime::traits::{MaybeSerializeDeserialize, Member};
  21. use sp_std::collections::btree_set::BTreeSet;
  22. // use sp_std::vec;
  23. use sp_std::vec::Vec;
  24. use system::ensure_signed;
  25. /// Type, used in diffrent numeric constraints representations
  26. pub type MaxNumber = u32;
  27. /// A numeric identifier trait
  28. pub trait NumericIdentifier:
  29. Parameter
  30. + Member
  31. + BaseArithmetic
  32. + Codec
  33. + Default
  34. + Copy
  35. + Clone
  36. + Hash
  37. + MaybeSerializeDeserialize
  38. + Eq
  39. + PartialEq
  40. + Ord
  41. + Zero
  42. {
  43. }
  44. impl NumericIdentifier for u64 {}
  45. /// Module configuration trait for this Substrate module.
  46. pub trait Trait: system::Trait + ActorAuthenticator + Clone {
  47. /// The overarching event type.
  48. type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
  49. /// EscrowAccountId seed for ModuleId to compute deterministic AccountId
  50. type ChannelOwnershipPaymentEscrowId: Get<[u8; 8]>;
  51. /// ChannelRevenueTreasury seed for ModuleId to compute deterministic AccountId
  52. type ChannelRevenueTreasuryId: Get<[u8; 8]>;
  53. /// Type of identifier for Videos
  54. type VideoId: NumericIdentifier;
  55. /// Type of identifier for Channels
  56. type ChannelId: NumericIdentifier;
  57. /// Type of identifier for Video Categories
  58. type VideoCategoryId: NumericIdentifier;
  59. /// Type of identifier for Channel Categories
  60. type ChannelCategoryId: NumericIdentifier;
  61. /// Type of identifier for Playlists
  62. type PlaylistId: NumericIdentifier;
  63. /// Type of identifier for Persons
  64. type PersonId: NumericIdentifier;
  65. /// Type of identifier for Channels
  66. type SeriesId: NumericIdentifier;
  67. /// Type of identifier for Channel transfer requests
  68. type ChannelTransferRequestId: NumericIdentifier;
  69. /// The maximum number of curators per group constraint
  70. type MaxNumberOfCuratorsPerGroup: Get<MaxNumber>;
  71. // Type that handles asset uploads to storage system
  72. // type StorageSysten = StorageSystemTrait;
  73. }
  74. // How new assets are to be added on creating and updating
  75. // Channels,Videos,Series and Person
  76. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  77. #[derive(Encode, Decode, Clone, PartialEq, Eq)]
  78. pub enum NewAsset<ContentParameters> {
  79. Upload(ContentParameters),
  80. Uri(Vec<u8>),
  81. }
  82. // === Channels
  83. // Must be convertible into new type StorageObjectOwner in storage system
  84. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  85. #[derive(Encode, Decode, Clone, PartialEq, Eq)]
  86. pub enum ChannelOwner<MemberId, CuratorGroupId> {
  87. Member(MemberId),
  88. CuratorGroup(CuratorGroupId),
  89. // Native DAO
  90. // Dao(DaoId),
  91. // EVM smart contract DAO
  92. // SmartContract(EthAddress)
  93. }
  94. impl<MemberId: Zero, CuratorGroupId> Default for ChannelOwner<MemberId, CuratorGroupId> {
  95. fn default() -> Self {
  96. ChannelOwner::Member(MemberId::zero())
  97. }
  98. }
  99. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  100. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  101. pub struct ChannelCategory {
  102. number_of_channels_in: u32,
  103. }
  104. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  105. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  106. pub struct ChannelCategoryCreationParameters {
  107. meta: Vec<u8>,
  108. }
  109. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  110. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  111. pub struct ChannelCategoryUpdateParameters {
  112. new_meta: Vec<u8>,
  113. }
  114. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  115. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  116. pub struct Channel<MemberId: Zero, CuratorGroupId, ChannelCategoryId> {
  117. owner: ChannelOwner<MemberId, CuratorGroupId>,
  118. in_category: ChannelCategoryId,
  119. number_of_videos: u32,
  120. number_of_playlists: u32,
  121. number_of_series: u32,
  122. // Only curator can update..
  123. is_curated: bool,
  124. // Balance of earnerned revenue yet to be withdrawn
  125. revenue: u128,
  126. }
  127. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  128. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  129. pub struct ChannelOwnershipTransferRequest<ChannelId, MemberId: Zero, CuratorGroupId> {
  130. channel_id: ChannelId,
  131. new_owner: ChannelOwner<MemberId, CuratorGroupId>,
  132. payment: u128,
  133. }
  134. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  135. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  136. pub struct ChannelCreationParameters<ChannelCategoryId> {
  137. in_category: ChannelCategoryId,
  138. meta: Vec<u8>,
  139. }
  140. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  141. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  142. pub struct ChannelUpdateParameters<ChannelCategoryId> {
  143. new_in_category: Option<ChannelCategoryId>,
  144. new_meta: Option<Vec<u8>>,
  145. }
  146. // === Videos
  147. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  148. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  149. pub struct VideoCategory {
  150. meta: Vec<u8>,
  151. number_of_videos_in_category: u32,
  152. }
  153. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  154. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  155. pub struct VideoCategoryCreationParameters {
  156. meta: Vec<u8>,
  157. }
  158. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  159. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  160. pub struct VideoCategoryUpdateParameters {
  161. new_meta: Vec<u8>,
  162. }
  163. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  164. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  165. pub struct VideoCreationParameters<VideoCategoryId> {
  166. in_category: VideoCategoryId,
  167. meta: Vec<u8>,
  168. }
  169. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  170. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  171. pub struct VideoUpdateParameters<VideoCategoryId> {
  172. new_in_category: Option<VideoCategoryId>,
  173. new_meta: Option<Vec<u8>>,
  174. }
  175. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  176. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  177. pub struct Video<ChannelId, SeriesId, PlaylistId> {
  178. in_channel: ChannelId,
  179. // keep track of which seasons and playlists which reference the video
  180. // - prevent removing a video if it is in a season (because order is important)
  181. // - remove from playlist on deletion
  182. in_series: Option<Vec<SeriesId>>,
  183. in_playlists: Option<Vec<PlaylistId>>,
  184. // Only curator can update..
  185. is_curated: bool,
  186. is_featured: bool,
  187. }
  188. // === Playlists
  189. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  190. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  191. pub struct PlaylistCreationParameters<VideoId> {
  192. videos: Vec<VideoId>,
  193. meta: Vec<u8>,
  194. }
  195. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  196. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  197. pub struct PlaylistUpdateParameters<VideoId> {
  198. // replace playlist with new collection
  199. new_videos: Option<Vec<VideoId>>,
  200. new_meta: Option<Vec<u8>>,
  201. }
  202. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  203. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  204. pub struct Playlist<ChannelId, VideoId> {
  205. in_channel: ChannelId,
  206. // collection of videos that make up the playlist
  207. videos: Vec<VideoId>,
  208. }
  209. // === Series
  210. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  211. #[derive(Encode, Decode, Clone, PartialEq, Eq)]
  212. pub enum EpisodeCreationParameters<VideoCategoryId, VideoId> {
  213. NewVideo(VideoCreationParameters<VideoCategoryId>),
  214. ExistingVideo(VideoId),
  215. }
  216. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  217. #[derive(Encode, Decode, Clone, PartialEq, Eq)]
  218. pub enum EpisodeUpdateParemters<VideoCategoryId, VideoId> {
  219. UpdateVideo(VideoUpdateParameters<VideoCategoryId>),
  220. ChangeExistingVideo(VideoId),
  221. }
  222. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  223. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  224. pub struct SeasonCreationParameters<VideoCategoryId, VideoId> {
  225. episodes: Vec<EpisodeCreationParameters<VideoCategoryId, VideoId>>,
  226. meta: Vec<u8>,
  227. }
  228. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  229. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  230. pub struct SeasonUpdateParameters<VideoCategoryId, VideoId> {
  231. new_episodes: Option<Vec<Option<EpisodeUpdateParemters<VideoCategoryId, VideoId>>>>,
  232. new_meta: Option<Vec<u8>>,
  233. }
  234. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  235. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  236. pub struct Season<VideoId> {
  237. episodes: Vec<VideoId>,
  238. }
  239. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  240. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  241. pub struct SeriesCreationParameters<VideoCategoryId, VideoId> {
  242. seasons: Vec<SeasonCreationParameters<VideoCategoryId, VideoId>>,
  243. meta: Vec<u8>,
  244. }
  245. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  246. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  247. pub struct SeriesUpdateParameters<VideoCategoryId, VideoId> {
  248. seasons: Option<Vec<Option<SeasonUpdateParameters<VideoCategoryId, VideoId>>>>,
  249. new_meta: Vec<u8>,
  250. }
  251. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  252. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  253. pub struct Series<ChannelId, VideoId> {
  254. in_channel: ChannelId,
  255. seasons: Vec<Season<VideoId>>,
  256. }
  257. // The authenticated origin for Person creation and updating calls
  258. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  259. #[derive(Encode, Decode, Clone, PartialEq, Eq)]
  260. pub enum PersonActor<MemberId, CuratorId> {
  261. Member(MemberId),
  262. Curator(CuratorId),
  263. }
  264. impl<MemberId: Zero, CuratorId> Default for PersonActor<MemberId, CuratorId> {
  265. fn default() -> Self {
  266. PersonActor::Member(MemberId::zero())
  267. }
  268. }
  269. // The authorized origin that may update or delete a Person
  270. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  271. #[derive(Encode, Decode, Clone, PartialEq, Eq)]
  272. pub enum PersonController<MemberId> {
  273. Member(MemberId),
  274. Curators,
  275. }
  276. impl<MemberId: Zero> Default for PersonController<MemberId> {
  277. fn default() -> Self {
  278. PersonController::Member(MemberId::zero())
  279. }
  280. }
  281. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  282. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  283. pub struct PersonCreationParameters {
  284. meta: Vec<u8>,
  285. }
  286. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  287. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  288. pub struct PersonUpdateParameters {
  289. new_meta: Option<Vec<u8>>,
  290. }
  291. #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
  292. #[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
  293. pub struct Person<MemberId: Zero> {
  294. controlled_by: PersonController<MemberId>,
  295. number_of_videos_person_involed_in: u32,
  296. }
  297. decl_storage! {
  298. trait Store for Module<T: Trait> as Content {
  299. pub ChannelById get(fn channel_by_id): map hasher(blake2_128_concat) T::ChannelId => Channel<T::MemberId, T::CuratorGroupId, T::ChannelCategoryId>;
  300. pub ChannelCategoryById get(fn channel_category_by_id): map hasher(blake2_128_concat) T::ChannelCategoryId => ChannelCategory;
  301. pub VideoById get(fn video_by_id): map hasher(blake2_128_concat) T::VideoId => Video<T::ChannelId, T::SeriesId, T::PlaylistId>;
  302. pub VideoCategoryById get(fn video_category_by_id): map hasher(blake2_128_concat) T::VideoCategoryId => VideoCategory;
  303. pub PlaylistById get(fn playlist_by_id): map hasher(blake2_128_concat) T::PlaylistId => Playlist<T::ChannelId, T::VideoId>;
  304. pub SeriesById get(fn series_by_id): map hasher(blake2_128_concat) T::SeriesId => Series<T::ChannelId, T::VideoId>;
  305. pub PersonById get(fn person_by_id): map hasher(blake2_128_concat) T::PersonId => Person<T::MemberId>;
  306. // pub PersonInVideo get(fn person_in_video): double_map hasher(blake2_128_concat) (T::VideoId, T::PersonId), hasher(blake2_128_concat) T::Hash => ();
  307. pub ChannelOwnershipTransferRequestById get(fn channel_ownership_transfer_request_by_id):
  308. map hasher(blake2_128_concat) T::ChannelTransferRequestId => ChannelOwnershipTransferRequest<T::ChannelId, T::MemberId, T::CuratorGroupId>;
  309. pub NextChannelCategoryId get(fn next_channel_category_id) config(): T::ChannelCategoryId;
  310. pub NextChannelId get(fn next_channel_id) config(): T::ChannelId;
  311. pub NextVideoCategoryId get(fn next_video_category_id) config(): T::VideoCategoryId;
  312. pub NextVideoId get(fn next_video_id) config(): T::VideoId;
  313. pub NextPlaylistId get(fn next_playlist_id) config(): T::PlaylistId;
  314. pub NextPersonId get(fn next_person_id) config(): T::PersonId;
  315. pub NextSeriesId get(fn next_series_id) config(): T::SeriesId;
  316. pub NextChannelTransferRequestId get(fn next_channel_transfer_request_id) config(): T::ChannelTransferRequestId;
  317. pub NextCuratorGroupId get(fn next_curator_group_id) config(): T::CuratorGroupId;
  318. /// Map, representing CuratorGroupId -> CuratorGroup relation
  319. pub CuratorGroupById get(fn curator_group_by_id): map hasher(blake2_128_concat) T::CuratorGroupId => CuratorGroup<T>;
  320. }
  321. }
  322. decl_module! {
  323. pub struct Module<T: Trait> for enum Call where origin: T::Origin {
  324. /// Predefined errors
  325. type Error = Error<T>;
  326. /// Initializing events
  327. fn deposit_event() = default;
  328. /// Exports const - max number of curators per group
  329. const MaxNumberOfCuratorsPerGroup: MaxNumber = T::MaxNumberOfCuratorsPerGroup::get();
  330. // ======
  331. // Next set of extrinsics can only be invoked by lead.
  332. // ======
  333. /// Add new curator group to runtime storage
  334. #[weight = 10_000_000] // TODO: adjust weight
  335. pub fn add_curator_group(
  336. origin,
  337. ) -> DispatchResult {
  338. // Ensure given origin is lead
  339. ensure_is_lead::<T>(origin)?;
  340. //
  341. // == MUTATION SAFE ==
  342. //
  343. let curator_group_id = Self::next_curator_group_id();
  344. // Insert empty curator group with `active` parameter set to false
  345. <CuratorGroupById<T>>::insert(curator_group_id, CuratorGroup::<T>::default());
  346. // Increment the next curator curator_group_id:
  347. <NextCuratorGroupId<T>>::mutate(|n| *n += T::CuratorGroupId::one());
  348. // Trigger event
  349. Self::deposit_event(RawEvent::CuratorGroupAdded(curator_group_id));
  350. Ok(())
  351. }
  352. /// Remove curator group under given `curator_group_id` from runtime storage
  353. #[weight = 10_000_000] // TODO: adjust weight
  354. pub fn remove_curator_group(
  355. origin,
  356. curator_group_id: T::CuratorGroupId,
  357. ) -> DispatchResult {
  358. // Ensure given origin is lead
  359. ensure_is_lead::<T>(origin)?;
  360. // Ensure CuratorGroup under given curator_group_id exists
  361. let curator_group = Self::ensure_curator_group_exists(&curator_group_id)?;
  362. // We should previously ensure that curator_group maintains no classes to be able to remove it
  363. curator_group.ensure_curator_group_maintains_no_classes()?;
  364. //
  365. // == MUTATION SAFE ==
  366. //
  367. // Remove curator group under given curator group id from runtime storage
  368. <CuratorGroupById<T>>::remove(curator_group_id);
  369. // Trigger event
  370. Self::deposit_event(RawEvent::CuratorGroupRemoved(curator_group_id));
  371. Ok(())
  372. }
  373. /// Set `is_active` status for curator group under given `curator_group_id`
  374. #[weight = 10_000_000] // TODO: adjust weight
  375. pub fn set_curator_group_status(
  376. origin,
  377. curator_group_id: T::CuratorGroupId,
  378. is_active: bool,
  379. ) -> DispatchResult {
  380. // Ensure given origin is lead
  381. ensure_is_lead::<T>(origin)?;
  382. // Ensure curator group under provided curator_group_id already exist
  383. Self::ensure_curator_group_under_given_id_exists(&curator_group_id)?;
  384. //
  385. // == MUTATION SAFE ==
  386. //
  387. // Set `is_active` status for curator group under given `curator_group_id`
  388. <CuratorGroupById<T>>::mutate(curator_group_id, |curator_group| {
  389. curator_group.set_status(is_active)
  390. });
  391. // Trigger event
  392. Self::deposit_event(RawEvent::CuratorGroupStatusSet(curator_group_id, is_active));
  393. Ok(())
  394. }
  395. /// Add curator to curator group under given `curator_group_id`
  396. #[weight = 10_000_000] // TODO: adjust weight
  397. pub fn add_curator_to_group(
  398. origin,
  399. curator_group_id: T::CuratorGroupId,
  400. curator_id: T::CuratorId,
  401. ) -> DispatchResult {
  402. // Ensure given origin is lead
  403. ensure_is_lead::<T>(origin)?;
  404. // Ensure curator group under provided curator_group_id already exist, retrieve corresponding one
  405. let curator_group = Self::ensure_curator_group_exists(&curator_group_id)?;
  406. // Ensure max number of curators per group limit not reached yet
  407. curator_group.ensure_max_number_of_curators_limit_not_reached()?;
  408. // Ensure curator under provided curator_id isn`t a CuratorGroup member yet
  409. curator_group.ensure_curator_in_group_does_not_exist(&curator_id)?;
  410. //
  411. // == MUTATION SAFE ==
  412. //
  413. // Insert curator_id into curator_group under given curator_group_id
  414. <CuratorGroupById<T>>::mutate(curator_group_id, |curator_group| {
  415. curator_group.get_curators_mut().insert(curator_id);
  416. });
  417. // Trigger event
  418. Self::deposit_event(RawEvent::CuratorAdded(curator_group_id, curator_id));
  419. Ok(())
  420. }
  421. /// Remove curator from a given curator group
  422. #[weight = 10_000_000] // TODO: adjust weight
  423. pub fn remove_curator_from_group(
  424. origin,
  425. curator_group_id: T::CuratorGroupId,
  426. curator_id: T::CuratorId,
  427. ) -> DispatchResult {
  428. // Ensure given origin is lead
  429. ensure_is_lead::<T>(origin)?;
  430. // Ensure curator group under provided curator_group_id already exist, retrieve corresponding one
  431. let curator_group = Self::ensure_curator_group_exists(&curator_group_id)?;
  432. // Ensure curator under provided curator_id is CuratorGroup member
  433. curator_group.ensure_curator_in_group_exists(&curator_id)?;
  434. //
  435. // == MUTATION SAFE ==
  436. //
  437. // Remove curator_id from curator_group under given curator_group_id
  438. <CuratorGroupById<T>>::mutate(curator_group_id, |curator_group| {
  439. curator_group.get_curators_mut().remove(&curator_id);
  440. });
  441. // Trigger event
  442. Self::deposit_event(RawEvent::CuratorRemoved(curator_group_id, curator_id));
  443. Ok(())
  444. }
  445. }
  446. }
  447. impl<T: Trait> Module<T> {
  448. /// Increment number of classes, maintained by each curator group
  449. pub fn increment_number_of_channels_owned_by_curator_groups(
  450. curator_group_ids: BTreeSet<T::CuratorGroupId>,
  451. ) {
  452. curator_group_ids.into_iter().for_each(|curator_group_id| {
  453. Self::increment_number_of_channels_owned_by_curator_group(curator_group_id);
  454. });
  455. }
  456. /// Decrement number of classes, maintained by each curator group
  457. pub fn decrement_number_of_channels_owned_by_curator_groups(
  458. curator_group_ids: BTreeSet<T::CuratorGroupId>,
  459. ) {
  460. curator_group_ids.into_iter().for_each(|curator_group_id| {
  461. Self::decrement_number_of_channels_owned_by_curator_group(curator_group_id);
  462. });
  463. }
  464. /// Increment number of classes, maintained by curator group
  465. pub fn increment_number_of_channels_owned_by_curator_group(
  466. curator_group_id: T::CuratorGroupId,
  467. ) {
  468. <CuratorGroupById<T>>::mutate(curator_group_id, |curator_group| {
  469. curator_group.increment_number_of_channels_owned_count();
  470. });
  471. }
  472. /// Decrement number of classes, maintained by curator group
  473. pub fn decrement_number_of_channels_owned_by_curator_group(
  474. curator_group_id: T::CuratorGroupId,
  475. ) {
  476. <CuratorGroupById<T>>::mutate(curator_group_id, |curator_group| {
  477. curator_group.decrement_number_of_channels_owned_count();
  478. });
  479. }
  480. /// Ensure `CuratorGroup` under given id exists
  481. pub fn ensure_curator_group_under_given_id_exists(
  482. curator_group_id: &T::CuratorGroupId,
  483. ) -> Result<(), Error<T>> {
  484. ensure!(
  485. <CuratorGroupById<T>>::contains_key(curator_group_id),
  486. Error::<T>::CuratorGroupDoesNotExist
  487. );
  488. Ok(())
  489. }
  490. /// Ensure `CuratorGroup` under given id exists, return corresponding one
  491. pub fn ensure_curator_group_exists(
  492. curator_group_id: &T::CuratorGroupId,
  493. ) -> Result<CuratorGroup<T>, Error<T>> {
  494. Self::ensure_curator_group_under_given_id_exists(curator_group_id)?;
  495. Ok(Self::curator_group_by_id(curator_group_id))
  496. }
  497. /// Ensure all `CuratorGroup`'s under given ids exist
  498. pub fn ensure_curator_groups_exist(
  499. curator_groups: &BTreeSet<T::CuratorGroupId>,
  500. ) -> Result<(), Error<T>> {
  501. for curator_group in curator_groups {
  502. // Ensure CuratorGroup under given id exists
  503. Self::ensure_curator_group_exists(curator_group)?;
  504. }
  505. Ok(())
  506. }
  507. }
  508. // Some initial config for the module on runtime upgrade
  509. impl<T: Trait> Module<T> {
  510. pub fn on_runtime_upgrade() {
  511. <NextChannelCategoryId<T>>::put(T::ChannelCategoryId::one());
  512. <NextVideoCategoryId<T>>::put(T::VideoCategoryId::one());
  513. <NextVideoId<T>>::put(T::VideoId::one());
  514. <NextChannelId<T>>::put(T::ChannelId::one());
  515. <NextPlaylistId<T>>::put(T::PlaylistId::one());
  516. <NextSeriesId<T>>::put(T::SeriesId::one());
  517. <NextPersonId<T>>::put(T::PersonId::one());
  518. <NextChannelTransferRequestId<T>>::put(T::ChannelTransferRequestId::one());
  519. }
  520. }
  521. decl_event!(
  522. pub enum Event<T>
  523. where
  524. CuratorGroupId = <T as ActorAuthenticator>::CuratorGroupId,
  525. CuratorId = <T as ActorAuthenticator>::CuratorId,
  526. {
  527. CuratorGroupAdded(CuratorGroupId),
  528. CuratorGroupRemoved(CuratorGroupId),
  529. CuratorGroupStatusSet(CuratorGroupId, bool),
  530. CuratorAdded(CuratorGroupId, CuratorId),
  531. CuratorRemoved(CuratorGroupId, CuratorId),
  532. }
  533. );