lib.rs 27 KB

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