Pārlūkot izejas kodu

Merge pull request #3 from Joystream/content_directory_second_try

Content directory second try
Arsen Kondratiev 4 gadi atpakaļ
vecāks
revīzija
c74df4ffbf

+ 19 - 3
Cargo.lock

@@ -2040,6 +2040,7 @@ dependencies = [
  "pallet-balances",
  "pallet-collective",
  "pallet-common",
+ "pallet-content-directory",
  "pallet-content-working-group",
  "pallet-finality-tracker",
  "pallet-forum",
@@ -3274,6 +3275,21 @@ dependencies = [
  "sp-runtime",
 ]
 
+[[package]]
+name = "pallet-content-directory"
+version = "3.0.0"
+dependencies = [
+ "frame-support",
+ "frame-system",
+ "parity-scale-codec",
+ "serde",
+ "sp-arithmetic",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-std",
+]
+
 [[package]]
 name = "pallet-content-working-group"
 version = "3.0.0"
@@ -3933,9 +3949,9 @@ dependencies = [
 
 [[package]]
 name = "parity-scale-codec-derive"
-version = "1.2.0"
+version = "1.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a0ec292e92e8ec7c58e576adacc1e3f399c597c8f263c42f18420abe58e7245"
+checksum = "198db82bb1c18fc00176004462dd809b2a6d851669550aa17af6dacd21ae0c14"
 dependencies = [
  "proc-macro-crate",
  "proc-macro2",
@@ -7796,4 +7812,4 @@ dependencies = [
  "quote 1.0.7",
  "syn 1.0.17",
  "synstructure",
-]
+]

+ 21 - 5
node/src/chain_spec.rs

@@ -30,11 +30,12 @@ use sp_runtime::Perbill;
 
 use node_runtime::{
     versioned_store::InputValidationLengthConstraint as VsInputValidation,
-    AuthorityDiscoveryConfig, BabeConfig, Balance, BalancesConfig, ContentWorkingGroupConfig,
-    CouncilConfig, CouncilElectionConfig, DataObjectStorageRegistryConfig,
-    DataObjectTypeRegistryConfig, ElectionParameters, GrandpaConfig, ImOnlineConfig, MembersConfig,
-    ProposalsCodexConfig, SessionConfig, SessionKeys, Signature, StakerStatus, StakingConfig,
-    StorageWorkingGroupConfig, SudoConfig, SystemConfig, VersionedStoreConfig, DAYS, WASM_BINARY,
+    AuthorityDiscoveryConfig, BabeConfig, Balance, BalancesConfig, ContentDirectoryConfig,
+    ContentDirectoryWorkingGroupConfig, ContentWorkingGroupConfig, CouncilConfig,
+    CouncilElectionConfig, DataObjectStorageRegistryConfig, DataObjectTypeRegistryConfig,
+    ElectionParameters, GrandpaConfig, ImOnlineConfig, MembersConfig, ProposalsCodexConfig,
+    SessionConfig, SessionKeys, Signature, StakerStatus, StakingConfig, StorageWorkingGroupConfig,
+    SudoConfig, SystemConfig, VersionedStoreConfig, DAYS, WASM_BINARY,
 };
 
 pub use node_runtime::{AccountId, GenesisConfig};
@@ -292,6 +293,13 @@ pub fn testnet_genesis(
             worker_application_human_readable_text_constraint: default_text_constraint,
             worker_exit_rationale_text_constraint: default_text_constraint,
         }),
+        working_group_Instance3: Some(ContentDirectoryWorkingGroupConfig {
+            phantom: Default::default(),
+            storage_working_group_mint_capacity: 0,
+            opening_human_readable_text_constraint: default_text_constraint,
+            worker_application_human_readable_text_constraint: default_text_constraint,
+            worker_exit_rationale_text_constraint: default_text_constraint,
+        }),
         versioned_store: Some(VersionedStoreConfig {
             class_by_id: vec![],
             entity_by_id: vec![],
@@ -326,6 +334,14 @@ pub fn testnet_genesis(
             channel_banner_constraint: InputValidationLengthConstraint::new(5, 1024),
             channel_title_constraint: InputValidationLengthConstraint::new(5, 1024),
         }),
+        content_directory: Some({
+            ContentDirectoryConfig {
+                curator_group_by_id: vec![],
+                next_class_id: 1,
+                next_entity_id: 1,
+                next_curator_group_id: 1,
+            }
+        }),
         proposals_codex: Some(ProposalsCodexConfig {
             set_validator_count_proposal_voting_period: cpcp
                 .set_validator_count_proposal_voting_period,

+ 2 - 2
runtime-modules/content-directory/src/class.rs

@@ -1,7 +1,7 @@
 use super::*;
 
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
+#[derive(Encode, Decode, Eq, PartialEq, Clone)]
 pub struct Class<T: Trait> {
     /// Permissions for an instance of a Class.
     class_permissions: ClassPermissions<T>,

+ 4 - 4
runtime-modules/content-directory/src/entity.rs

@@ -1,8 +1,8 @@
 use super::*;
 
 /// Represents `Entity`, related to a specific `Class`
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
+#[derive(Encode, Decode, Clone, PartialEq, Eq)]
 pub struct Entity<T: Trait> {
     /// Permissions for an instance of an Entity.
     entity_permissions: EntityPermissions<T>,
@@ -165,8 +165,8 @@ impl<T: Trait> Entity<T> {
 }
 
 /// Structure, respresenting inbound entity rcs for each `Entity`
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Copy, Debug)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Copy)]
 pub struct InboundReferenceCounter {
     /// Total number of inbound references from another entities
     pub total: u32,

+ 8 - 8
runtime-modules/content-directory/src/helpers.rs

@@ -170,8 +170,8 @@ impl<'a, T: Trait> StoredValuesForExistingProperties<'a, T> {
 }
 
 /// Length constraint for input validation
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Default, Clone, Copy, PartialEq, Eq, Debug)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
+#[derive(Encode, Decode, Default, Clone, Copy, PartialEq, Eq)]
 pub struct InputValidationLengthConstraint {
     /// Minimum length
     min: u16,
@@ -185,7 +185,7 @@ pub struct InputValidationLengthConstraint {
 
 impl InputValidationLengthConstraint {
     /// Create new `InputValidationLengthConstraint` constraint
-    pub fn new(min: u16, max_min_diff: u16) -> Self {
+    pub const fn new(min: u16, max_min_diff: u16) -> Self {
         Self { min, max_min_diff }
     }
 
@@ -218,7 +218,7 @@ impl InputValidationLengthConstraint {
 }
 
 /// Enum, used to specify, which mode of operation should be chosen
-#[derive(Clone, PartialEq, Eq, Copy, Debug)]
+#[derive(Clone, PartialEq, Eq, Copy)]
 pub enum DeltaMode {
     Increment,
     Decrement,
@@ -231,8 +231,8 @@ impl Default for DeltaMode {
 }
 
 /// Representing delta on which respective `InboundReferenceCounter` should be changed.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Default, PartialEq, Eq, Debug)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
+#[derive(Encode, Decode, Default, PartialEq, Eq)]
 pub struct EntityReferenceCounterSideEffect {
     /// Delta number of all inbound references from another entities
     pub total: i32,
@@ -281,8 +281,8 @@ impl AddAssign for EntityReferenceCounterSideEffect {
 }
 
 /// The net side effect on a set of entities from some operations.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
+#[derive(Encode, Decode, Clone, PartialEq, Eq)]
 pub struct ReferenceCounterSideEffects<T: Trait>(
     BTreeMap<T::EntityId, EntityReferenceCounterSideEffect>,
 );

+ 8 - 14
runtime-modules/content-directory/src/lib.rs

@@ -135,7 +135,6 @@ pub use operations::*;
 pub use permissions::*;
 pub use schema::*;
 
-use core::fmt::Debug;
 use core::hash::Hash;
 use core::ops::AddAssign;
 
@@ -145,24 +144,25 @@ use frame_support::storage::IterableStorageMap;
 use frame_support::{
     decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure, traits::Get, Parameter,
 };
+#[cfg(feature = "std")]
+pub use serde::{Deserialize, Serialize};
 use sp_arithmetic::traits::{BaseArithmetic, One, Zero};
 use sp_runtime::traits::{MaybeSerializeDeserialize, Member};
+use sp_std::borrow::ToOwned;
 use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet};
+use sp_std::vec;
 use sp_std::vec::Vec;
 use system::ensure_signed;
 
-#[cfg(feature = "std")]
-pub use serde::{Deserialize, Serialize};
-
 pub use errors::Error;
 
 use core::debug_assert;
 
 /// Type, used in diffrent numeric constraints representations
-type MaxNumber = u32;
+pub type MaxNumber = u32;
 
 /// Module configuration trait for this Substrate module.
-pub trait Trait: system::Trait + ActorAuthenticator + Debug + Clone {
+pub trait Trait: system::Trait + ActorAuthenticator + Clone {
     /// The overarching event type.
     type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
 
@@ -174,8 +174,6 @@ pub trait Trait: system::Trait + ActorAuthenticator + Debug + Clone {
         + Default
         + Copy
         + Clone
-        + One
-        + Zero
         + MaybeSerializeDeserialize
         + Eq
         + PartialEq
@@ -190,9 +188,7 @@ pub trait Trait: system::Trait + ActorAuthenticator + Debug + Clone {
         + Default
         + Copy
         + Clone
-        + One
         + Hash
-        + Zero
         + MaybeSerializeDeserialize
         + Eq
         + PartialEq
@@ -207,8 +203,6 @@ pub trait Trait: system::Trait + ActorAuthenticator + Debug + Clone {
         + Copy
         + Clone
         + Hash
-        + One
-        + Zero
         + MaybeSerializeDeserialize
         + Eq
         + PartialEq
@@ -266,10 +260,10 @@ decl_storage! {
     trait Store for Module<T: Trait> as ContentDirectory {
 
         /// Map, representing ClassId -> Class relation
-        pub ClassById get(fn class_by_id) config(): map hasher(blake2_128_concat) T::ClassId => Class<T>;
+        pub ClassById get(fn class_by_id): map hasher(blake2_128_concat) T::ClassId => Class<T>;
 
         /// Map, representing EntityId -> Entity relation
-        pub EntityById get(fn entity_by_id) config(): map hasher(blake2_128_concat) T::EntityId => Entity<T>;
+        pub EntityById get(fn entity_by_id): map hasher(blake2_128_concat) T::EntityId => Entity<T>;
 
         /// Map, representing  CuratorGroupId -> CuratorGroup relation
         pub CuratorGroupById get(fn curator_group_by_id) config(): map hasher(blake2_128_concat) T::CuratorGroupId => CuratorGroup<T>;

+ 0 - 31
runtime-modules/content-directory/src/mock.rs

@@ -89,21 +89,16 @@ thread_local! {
     static PROPERTY_DESCRIPTION_CONSTRAINT: RefCell<InputValidationLengthConstraint> = RefCell::new(InputValidationLengthConstraint::default());
     static CLASS_NAME_CONSTRAINT: RefCell<InputValidationLengthConstraint> = RefCell::new(InputValidationLengthConstraint::default());
     static CLASS_DESCRIPTION_CONSTRAINT: RefCell<InputValidationLengthConstraint> = RefCell::new(InputValidationLengthConstraint::default());
-
     static MAX_NUMBER_OF_CLASSES: RefCell<MaxNumber> = RefCell::new(0);
     static MAX_NUMBER_OF_MAINTAINERS_PER_CLASS: RefCell<MaxNumber> = RefCell::new(0);
     static MAX_NUMBER_OF_SCHEMAS_PER_CLASS: RefCell<MaxNumber> = RefCell::new(0);
     static MAX_NUMBER_OF_PROPERTIES_PER_CLASS: RefCell<MaxNumber> = RefCell::new(0);
     static MAX_NUMBER_OF_ENTITIES_PER_CLASS: RefCell<EntityId> = RefCell::new(0);
-
     static MAX_NUMBER_OF_CURATORS_PER_GROUP: RefCell<MaxNumber> = RefCell::new(0);
-
     static MAX_NUMBER_OF_OPERATIONS_DURING_ATOMIC_BATCHING: RefCell<MaxNumber> = RefCell::new(0);
-
     static VEC_MAX_LENGTH_CONSTRAINT: RefCell<VecMaxLength> = RefCell::new(0);
     static TEXT_MAX_LENGTH_CONSTRAINT: RefCell<TextMaxLength> = RefCell::new(0);
     static HASHED_TEXT_MAX_LENGTH_CONSTRAINT: RefCell<HashedTextMaxLength> = RefCell::new(Some(0));
-
     static INDIVIDUAL_ENTITIES_CREATION_LIMIT: RefCell<EntityId> = RefCell::new(0);
 }
 
@@ -252,31 +247,23 @@ impl_outer_event! {
 
 impl Trait for Runtime {
     type Event = TestEvent;
-
     type Nonce = u64;
-
     type ClassId = u64;
     type EntityId = u64;
-
     type PropertyNameLengthConstraint = PropertyNameLengthConstraint;
     type PropertyDescriptionLengthConstraint = PropertyDescriptionLengthConstraint;
     type ClassNameLengthConstraint = ClassNameLengthConstraint;
     type ClassDescriptionLengthConstraint = ClassDescriptionLengthConstraint;
-
     type MaxNumberOfClasses = MaxNumberOfClasses;
     type MaxNumberOfMaintainersPerClass = MaxNumberOfMaintainersPerClass;
     type MaxNumberOfSchemasPerClass = MaxNumberOfSchemasPerClass;
     type MaxNumberOfPropertiesPerSchema = MaxNumberOfPropertiesPerSchema;
     type MaxNumberOfEntitiesPerClass = MaxNumberOfEntitiesPerClass;
-
     type MaxNumberOfCuratorsPerGroup = MaxNumberOfCuratorsPerGroup;
-
     type MaxNumberOfOperationsDuringAtomicBatching = MaxNumberOfOperationsDuringAtomicBatching;
-
     type VecMaxLengthConstraint = VecMaxLengthConstraint;
     type TextMaxLengthConstraint = TextMaxLengthConstraint;
     type HashedTextMaxLengthConstraint = HashedTextMaxLengthConstraint;
-
     type IndividualEntitiesCreationLimit = IndividualEntitiesCreationLimit;
 }
 
@@ -311,21 +298,16 @@ pub struct ExtBuilder {
     property_description_constraint: InputValidationLengthConstraint,
     class_name_constraint: InputValidationLengthConstraint,
     class_description_constraint: InputValidationLengthConstraint,
-
     max_number_of_classes: MaxNumber,
     max_number_of_maintainers_per_class: MaxNumber,
     max_number_of_schemas_per_class: MaxNumber,
     max_number_of_properties_per_class: MaxNumber,
     max_number_of_entities_per_class: EntityId,
-
     max_number_of_curators_per_group: MaxNumber,
-
     max_number_of_operations_during_atomic_batching: MaxNumber,
-
     vec_max_length_constraint: VecMaxLength,
     text_max_length_constraint: TextMaxLength,
     hashed_text_max_length_constraint: HashedTextMaxLength,
-
     individual_entities_creation_limit: EntityId,
 }
 
@@ -336,21 +318,16 @@ impl Default for ExtBuilder {
             property_description_constraint: InputValidationLengthConstraint::new(1, 500),
             class_name_constraint: InputValidationLengthConstraint::new(1, 49),
             class_description_constraint: InputValidationLengthConstraint::new(1, 500),
-
             max_number_of_classes: 100,
             max_number_of_maintainers_per_class: 10,
             max_number_of_schemas_per_class: 20,
             max_number_of_properties_per_class: 40,
             max_number_of_entities_per_class: 400,
-
             max_number_of_curators_per_group: 50,
-
             max_number_of_operations_during_atomic_batching: 500,
-
             vec_max_length_constraint: 200,
             text_max_length_constraint: 5000,
             hashed_text_max_length_constraint: Some(25000),
-
             individual_entities_creation_limit: 50,
         }
     }
@@ -363,7 +340,6 @@ impl ExtBuilder {
             .with(|v| *v.borrow_mut() = self.property_description_constraint);
         CLASS_NAME_CONSTRAINT.with(|v| *v.borrow_mut() = self.class_name_constraint);
         CLASS_DESCRIPTION_CONSTRAINT.with(|v| *v.borrow_mut() = self.class_description_constraint);
-
         MAX_NUMBER_OF_CLASSES.with(|v| *v.borrow_mut() = self.max_number_of_classes);
         MAX_NUMBER_OF_MAINTAINERS_PER_CLASS
             .with(|v| *v.borrow_mut() = self.max_number_of_maintainers_per_class);
@@ -373,19 +349,14 @@ impl ExtBuilder {
             .with(|v| *v.borrow_mut() = self.max_number_of_properties_per_class);
         MAX_NUMBER_OF_ENTITIES_PER_CLASS
             .with(|v| *v.borrow_mut() = self.max_number_of_entities_per_class);
-
         MAX_NUMBER_OF_CURATORS_PER_GROUP
             .with(|v| *v.borrow_mut() = self.max_number_of_curators_per_group);
-
         MAX_NUMBER_OF_OPERATIONS_DURING_ATOMIC_BATCHING
             .with(|v| *v.borrow_mut() = self.max_number_of_operations_during_atomic_batching);
-
         VEC_MAX_LENGTH_CONSTRAINT.with(|v| *v.borrow_mut() = self.vec_max_length_constraint);
         TEXT_MAX_LENGTH_CONSTRAINT.with(|v| *v.borrow_mut() = self.text_max_length_constraint);
-
         HASHED_TEXT_MAX_LENGTH_CONSTRAINT
             .with(|v| *v.borrow_mut() = self.hashed_text_max_length_constraint);
-
         INDIVIDUAL_ENTITIES_CREATION_LIMIT
             .with(|v| *v.borrow_mut() = self.individual_entities_creation_limit);
     }
@@ -405,8 +376,6 @@ impl ExtBuilder {
 
 fn default_content_directory_genesis_config() -> GenesisConfig<Runtime> {
     GenesisConfig {
-        class_by_id: vec![],
-        entity_by_id: vec![],
         curator_group_by_id: vec![],
         next_class_id: 1,
         next_entity_id: 1,

+ 13 - 7
runtime-modules/content-directory/src/operations.rs

@@ -4,7 +4,7 @@ use sp_std::collections::btree_map::BTreeMap;
 use sp_std::prelude::*;
 
 /// Parametrized entity property value
-#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug)]
+#[derive(Encode, Decode, Eq, PartialEq, Clone)]
 pub enum ParametrizedPropertyValue<T: Trait> {
     /// Same fields as normal InputPropertyValue
     InputPropertyValue(InputPropertyValue<T>),
@@ -17,14 +17,14 @@ pub enum ParametrizedPropertyValue<T: Trait> {
 }
 
 /// Parametrized entity
-#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug)]
+#[derive(Encode, Decode, Eq, PartialEq, Clone)]
 pub enum ParameterizedEntity<T: Trait> {
     InternalEntityJustAdded(u32),
     ExistingEntity(T::EntityId),
 }
 
 /// Parametrized class property value
-#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug)]
+#[derive(Encode, Decode, Eq, PartialEq, Clone)]
 pub struct ParametrizedClassPropertyValue<T: Trait> {
     /// Index is into properties vector of class.
     pub in_class_index: PropertyId,
@@ -34,14 +34,14 @@ pub struct ParametrizedClassPropertyValue<T: Trait> {
 }
 
 /// Operation, that represents `Entity` creation
-#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug)]
+#[derive(Encode, Decode, Eq, PartialEq, Clone)]
 pub struct CreateEntityOperation<T: Trait> {
     /// Class of an Entity
     pub class_id: T::ClassId,
 }
 
 /// Operation, that represents property values update
-#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug)]
+#[derive(Encode, Decode, Eq, PartialEq, Clone)]
 pub struct UpdatePropertyValuesOperation<T: Trait> {
     /// Entity id to perfrom operation
     pub entity_id: ParameterizedEntity<T>,
@@ -50,7 +50,7 @@ pub struct UpdatePropertyValuesOperation<T: Trait> {
 }
 
 /// Operation, that represents adding `Entity` `Schema` support
-#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug)]
+#[derive(Encode, Decode, Eq, PartialEq, Clone)]
 pub struct AddSchemaSupportToEntityOperation<T: Trait> {
     /// Entity id to perfrom operation
     pub entity_id: ParameterizedEntity<T>,
@@ -61,13 +61,19 @@ pub struct AddSchemaSupportToEntityOperation<T: Trait> {
 }
 
 /// The type of operation performed
-#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug)]
+#[derive(Encode, Decode, Eq, PartialEq, Clone)]
 pub enum OperationType<T: Trait> {
     CreateEntity(CreateEntityOperation<T>),
     UpdatePropertyValues(UpdatePropertyValuesOperation<T>),
     AddSchemaSupportToEntity(AddSchemaSupportToEntityOperation<T>),
 }
 
+impl<T: Trait> core::fmt::Debug for OperationType<T> {
+    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(formatter, "OperationType {:?}", self)
+    }
+}
+
 /// Retrieve entity_id of parametrized `Entity`
 pub fn parametrized_entity_to_entity_id<T: Trait>(
     created_entities: &BTreeMap<usize, T::EntityId>,

+ 8 - 3
runtime-modules/content-directory/src/permissions.rs

@@ -19,7 +19,7 @@ use sp_arithmetic::traits::BaseArithmetic;
 use sp_runtime::traits::{MaybeSerializeDeserialize, Member};
 
 /// Model of authentication manager.
-pub trait ActorAuthenticator: system::Trait + Debug {
+pub trait ActorAuthenticator: system::Trait {
     /// Curator identifier
     type CuratorId: Parameter
         + Member
@@ -51,7 +51,6 @@ pub trait ActorAuthenticator: system::Trait + Debug {
         + Member
         + BaseArithmetic
         + Codec
-        + One
         + Default
         + Copy
         + Clone
@@ -108,7 +107,7 @@ pub fn ensure_is_lead<T: Trait>(origin: T::Origin) -> DispatchResult {
 
 /// Enum, representing all possible `Actor`s
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Eq, PartialEq, Clone, Copy, Debug)]
+#[derive(Encode, Decode, Eq, PartialEq, Clone, Copy)]
 pub enum Actor<T: Trait> {
     Curator(T::CuratorGroupId, T::CuratorId),
     Member(T::MemberId),
@@ -120,3 +119,9 @@ impl<T: Trait> Default for Actor<T> {
         Self::Lead
     }
 }
+
+impl<T: Trait> core::fmt::Debug for Actor<T> {
+    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(formatter, "Actor {:?}", self)
+    }
+}

+ 7 - 1
runtime-modules/content-directory/src/permissions/class.rs

@@ -2,7 +2,7 @@ use super::*;
 
 /// Permissions for an instance of a `Class` in the versioned store.
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug)]
+#[derive(Encode, Decode, Eq, PartialEq, Clone)]
 pub struct ClassPermissions<T: Trait> {
     /// For this permission, the individual member is allowed to create the entity and become controller.
     any_member: bool,
@@ -23,6 +23,12 @@ pub struct ClassPermissions<T: Trait> {
     maintainers: BTreeSet<T::CuratorGroupId>,
 }
 
+impl<T: Trait> core::fmt::Debug for ClassPermissions<T> {
+    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(formatter, "ClassPermissions {:?}", self)
+    }
+}
+
 impl<T: Trait> Default for ClassPermissions<T> {
     fn default() -> Self {
         Self {

+ 2 - 2
runtime-modules/content-directory/src/permissions/curator_group.rs

@@ -1,8 +1,8 @@
 use super::*;
 
 /// A group, that consists of `curators` set
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Eq, PartialEq, Clone, Debug)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
+#[derive(Encode, Decode, Eq, PartialEq, Clone)]
 pub struct CuratorGroup<T: Trait> {
     /// Curators set, associated with a iven curator group
     curators: BTreeSet<T::CuratorId>,

+ 10 - 4
runtime-modules/content-directory/src/permissions/entity.rs

@@ -2,7 +2,7 @@ use super::*;
 
 /// Owner of an `Entity`.
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, Debug)]
+#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq)]
 pub enum EntityController<T: Trait> {
     Maintainers,
     Member(T::MemberId),
@@ -26,9 +26,15 @@ impl<T: Trait> Default for EntityController<T> {
     }
 }
 
+impl<T: Trait> core::fmt::Debug for EntityController<T> {
+    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(formatter, "EntityController {:?}", self)
+    }
+}
+
 /// Permissions for a given entity.
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
+#[derive(Encode, Decode, Clone, PartialEq, Eq)]
 pub struct EntityPermissions<T: Trait> {
     /// Current controller, which is initially set based on who created entity
     pub controller: EntityController<T>,
@@ -115,7 +121,7 @@ impl<T: Trait> EntityPermissions<T> {
 }
 
 /// Type, derived from dispatchable call, identifies the caller
-#[derive(Encode, Decode, Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Debug)]
+#[derive(Encode, Decode, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
 pub enum EntityAccessLevel {
     /// Caller identified as the entity maintainer
     EntityMaintainer,

+ 17 - 11
runtime-modules/content-directory/src/schema.rs

@@ -31,8 +31,8 @@ pub type SchemaId = u16;
 pub type SameController = bool;
 
 /// Locking policy, representing `Property` locking status for both controller and maintainer
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Default, Decode, Clone, Copy, PartialEq, Eq, Debug)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
+#[derive(Encode, Default, Decode, Clone, Copy, PartialEq, Eq)]
 pub struct PropertyLockingPolicy {
     /// If property is locked from maintainer
     pub is_locked_from_maintainer: bool,
@@ -41,8 +41,8 @@ pub struct PropertyLockingPolicy {
 }
 
 /// Enum, used for `PropertyType` representation
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, Debug)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
+#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq)]
 pub enum Type<T: Trait> {
     Bool,
     Uint16,
@@ -86,8 +86,8 @@ impl<T: Trait> Type<T> {
 }
 
 /// Vector property type representation
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, Debug)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
+#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq)]
 pub struct VecPropertyType<T: Trait> {
     vec_type: Type<T>,
     /// Max length of vector, corresponding to a given type
@@ -134,8 +134,8 @@ impl<T: Trait> VecPropertyType<T> {
 }
 
 /// Enum, representing either `Type` or `VecPropertyType`
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq, Debug)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
+#[derive(Encode, Decode, Clone, Copy, PartialEq, Eq)]
 pub enum PropertyType<T: Trait> {
     Single(Type<T>),
     Vector(VecPropertyType<T>),
@@ -183,8 +183,8 @@ impl<T: Trait> PropertyType<T> {
 }
 
 /// A schema defines what properties describe an entity
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
+#[derive(Encode, Decode, Clone, PartialEq, Eq)]
 pub struct Schema {
     /// Indices into properties vector for the corresponding class.
     properties: BTreeSet<PropertyId>,
@@ -257,7 +257,7 @@ impl Schema {
 
 /// `Property` representation, related to a given `Class`
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
+#[derive(Encode, Decode, Clone, PartialEq, Eq)]
 pub struct Property<T: Trait> {
     /// The type of `Property`
     pub property_type: PropertyType<T>,
@@ -286,6 +286,12 @@ impl<T: Trait> Default for Property<T> {
     }
 }
 
+impl<T: Trait> core::fmt::Debug for Property<T> {
+    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(formatter, "Property {:?}", self)
+    }
+}
+
 impl<T: Trait> Property<T> {
     /// Check if property is locked from actor with provided `EntityAccessLevel`
     pub fn is_locked_from(&self, access_level: EntityAccessLevel) -> bool {

+ 16 - 4
runtime-modules/content-directory/src/schema/input.rs

@@ -2,12 +2,18 @@ use super::*;
 
 /// Enum, representing either `SingleInputPropertyValue` or `VecInputPropertyValue`
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
+#[derive(Encode, Decode, Clone, PartialEq, Eq)]
 pub enum InputPropertyValue<T: Trait> {
     Single(InputValue<T>),
     Vector(VecInputValue<T>),
 }
 
+impl<T: Trait> core::fmt::Debug for InputPropertyValue<T> {
+    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+        write!(formatter, "InputPropertyValue {:?}", self)
+    }
+}
+
 impl<T: Trait> InputPropertyValue<T> {
     pub fn as_single_value(&self) -> Option<&InputValue<T>> {
         if let InputPropertyValue::Single(single_value) = self {
@@ -58,7 +64,7 @@ impl<T: Trait> Default for InputPropertyValue<T> {
 
 /// InputValue enum representation, related to corresponding `SingleInputPropertyValue` structure
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
+#[derive(Encode, Decode, Clone, PartialEq, Eq)]
 pub enum InputValue<T: Trait> {
     Bool(bool),
     Uint16(u16),
@@ -73,6 +79,12 @@ pub enum InputValue<T: Trait> {
     Reference(T::EntityId),
 }
 
+impl<T: Trait> core::fmt::Debug for InputValue<T> {
+    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> sp_std::fmt::Result {
+        write!(formatter, "InputValue {:?}", self)
+    }
+}
+
 impl<T: Trait> Default for InputValue<T> {
     fn default() -> InputValue<T> {
         Self::Bool(false)
@@ -91,8 +103,8 @@ impl<T: Trait> InputValue<T> {
 }
 
 /// Vector value enum representation
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
+#[derive(Encode, Decode, Clone, PartialEq, Eq)]
 pub enum VecInputValue<T: Trait> {
     Bool(Vec<bool>),
     Uint16(Vec<u16>),

+ 8 - 8
runtime-modules/content-directory/src/schema/output.rs

@@ -2,8 +2,8 @@ use super::*;
 use sp_runtime::traits::Hash;
 
 /// Enum, representing either `StoredValue` or `VecStoredPropertyValue`
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, PartialEq, Eq, Debug)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
+#[derive(Encode, Decode, Clone, PartialEq, Eq)]
 pub enum StoredPropertyValue<T: Trait> {
     Single(StoredValue<T>),
     Vector(VecStoredPropertyValue<T>),
@@ -84,8 +84,8 @@ impl<T: Trait> Default for StoredPropertyValue<T> {
 }
 
 /// StoredValue enum representation, related to corresponding `SingleStoredPropertyValue` structure
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Hash, Clone, PartialEq, PartialOrd, Ord, Eq, Debug)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
+#[derive(Encode, Decode, Hash, Clone, PartialEq, PartialOrd, Ord, Eq)]
 pub enum StoredValue<T: Trait> {
     Bool(bool),
     Uint16(u16),
@@ -117,8 +117,8 @@ impl<T: Trait> StoredValue<T> {
 }
 
 /// Consists of `VecStoredPropertyValue` enum representation and `nonce`, used to avoid vector data race update conditions
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Default, Clone, Debug, PartialEq, Eq)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq)]
 pub struct VecStoredPropertyValue<T: Trait> {
     vec_value: VecStoredValue<T>,
     nonce: T::Nonce,
@@ -276,8 +276,8 @@ impl<T: Trait> VecStoredPropertyValue<T> {
 }
 
 /// Vector value enum representation, related to corresponding `VecStoredPropertyValue` structure
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-#[derive(Encode, Decode, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
+#[derive(Encode, Decode, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub enum VecStoredValue<T: Trait> {
     Bool(Vec<bool>),
     Uint16(Vec<u16>),

+ 2 - 1
runtime-modules/working-group/src/lib.rs

@@ -1298,7 +1298,8 @@ impl<T: Trait<I>, I: Instance> Module<T, I> {
         Ok(worker)
     }
 
-    fn ensure_worker_exists(worker_id: &WorkerId<T>) -> Result<WorkerOf<T>, Error<T, I>> {
+    /// Ensures worker under given id already exists
+    pub fn ensure_worker_exists(worker_id: &WorkerId<T>) -> Result<WorkerOf<T>, Error<T, I>> {
         ensure!(
             WorkerById::<T, I>::contains_key(worker_id),
             Error::<T, I>::WorkerDoesNotExist

+ 2 - 0
runtime/Cargo.toml

@@ -77,6 +77,7 @@ service-discovery = { package = 'pallet-service-discovery', default-features = f
 proposals-engine = { package = 'pallet-proposals-engine', default-features = false, path = '../runtime-modules/proposals/engine'}
 proposals-discussion = { package = 'pallet-proposals-discussion', default-features = false, path = '../runtime-modules/proposals/discussion'}
 proposals-codex = { package = 'pallet-proposals-codex', default-features = false, path = '../runtime-modules/proposals/codex'}
+content-directory = { package = 'pallet-content-directory', default-features = false, path = '../runtime-modules/content-directory' }
 
 [dev-dependencies]
 sp-io = { package = 'sp-io', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = '00768a1f21a579c478fe5d4f51e1fa71f7db9fd4'}
@@ -152,6 +153,7 @@ std = [
     'proposals-engine/std',
     'proposals-discussion/std',
     'proposals-codex/std',
+    'content-directory/std',
 ]
 runtime-benchmarks = [
     "system/runtime-benchmarks",

+ 44 - 0
runtime/src/integration/content_directory.rs

@@ -0,0 +1,44 @@
+use crate::{AccountId, ContentDirectoryWorkingGroupInstance, MemberId, Runtime};
+
+// Alias for content directory working group
+pub(crate) type ContentDirectoryWorkingGroup<T> =
+    working_group::Module<T, ContentDirectoryWorkingGroupInstance>;
+
+impl content_directory::ActorAuthenticator for Runtime {
+    type CuratorId = u64;
+    type MemberId = MemberId;
+    type CuratorGroupId = u64;
+
+    fn is_lead(account_id: &AccountId) -> bool {
+        // get current lead id
+        let maybe_current_lead_id = ContentDirectoryWorkingGroup::<Runtime>::current_lead();
+        if let Some(ref current_lead_id) = maybe_current_lead_id {
+            if let Ok(worker) =
+                ContentDirectoryWorkingGroup::<Runtime>::ensure_worker_exists(current_lead_id)
+            {
+                *account_id == worker.role_account_id
+            } else {
+                false
+            }
+        } else {
+            false
+        }
+    }
+
+    fn is_curator(curator_id: &Self::CuratorId, account_id: &AccountId) -> bool {
+        if let Ok(worker) =
+            ContentDirectoryWorkingGroup::<Runtime>::ensure_worker_exists(curator_id)
+        {
+            *account_id == worker.role_account_id
+        } else {
+            false
+        }
+    }
+
+    fn is_member(member_id: &Self::MemberId, account_id: &AccountId) -> bool {
+        membership::Module::<Runtime>::ensure_is_controller_account_for_member(
+            member_id, account_id,
+        )
+        .is_ok()
+    }
+}

+ 1 - 0
runtime/src/integration/mod.rs

@@ -1,3 +1,4 @@
+pub mod content_directory;
 pub mod content_working_group;
 pub mod forum;
 pub mod proposals;

+ 60 - 1
runtime/src/lib.rs

@@ -62,6 +62,11 @@ pub use proposals_codex::ProposalsConfigParameters;
 pub use versioned_store;
 pub use working_group;
 
+pub use content_directory;
+pub use content_directory::{
+    HashedTextMaxLength, InputValidationLengthConstraint, MaxNumber, TextMaxLength, VecMaxLength,
+};
+
 /// This runtime version.
 pub const VERSION: RuntimeVersion = RuntimeVersion {
     spec_name: create_runtime_str!("joystream-node"),
@@ -372,6 +377,48 @@ impl versioned_store_permissions::Trait for Runtime {
         integration::versioned_store_permissions::ContentLeadOrSudoKeyCanCreateClasses;
 }
 
+type EntityId = <Runtime as content_directory::Trait>::EntityId;
+
+parameter_types! {
+    pub const PropertyNameLengthConstraint: InputValidationLengthConstraint = InputValidationLengthConstraint::new(1, 49);
+    pub const PropertyDescriptionLengthConstraint: InputValidationLengthConstraint = InputValidationLengthConstraint::new(1, 500);
+    pub const ClassNameLengthConstraint: InputValidationLengthConstraint = InputValidationLengthConstraint::new(1, 49);
+    pub const ClassDescriptionLengthConstraint: InputValidationLengthConstraint = InputValidationLengthConstraint::new(1, 500);
+    pub const MaxNumberOfClasses: MaxNumber = 100;
+    pub const MaxNumberOfMaintainersPerClass: MaxNumber = 10;
+    pub const MaxNumberOfSchemasPerClass: MaxNumber = 20;
+    pub const MaxNumberOfPropertiesPerSchema: MaxNumber = 40;
+    pub const MaxNumberOfEntitiesPerClass: MaxNumber = 400;
+    pub const MaxNumberOfCuratorsPerGroup: MaxNumber = 50;
+    pub const MaxNumberOfOperationsDuringAtomicBatching: MaxNumber = 500;
+    pub const VecMaxLengthConstraint: VecMaxLength = 200;
+    pub const TextMaxLengthConstraint: TextMaxLength = 5000;
+    pub const HashedTextMaxLengthConstraint: HashedTextMaxLength = Some(25000);
+    pub const IndividualEntitiesCreationLimit: EntityId = 50;
+}
+
+impl content_directory::Trait for Runtime {
+    type Event = Event;
+    type Nonce = u64;
+    type ClassId = u64;
+    type EntityId = u64;
+    type PropertyNameLengthConstraint = PropertyNameLengthConstraint;
+    type PropertyDescriptionLengthConstraint = PropertyDescriptionLengthConstraint;
+    type ClassNameLengthConstraint = ClassNameLengthConstraint;
+    type ClassDescriptionLengthConstraint = ClassDescriptionLengthConstraint;
+    type MaxNumberOfClasses = MaxNumberOfClasses;
+    type MaxNumberOfMaintainersPerClass = MaxNumberOfMaintainersPerClass;
+    type MaxNumberOfSchemasPerClass = MaxNumberOfSchemasPerClass;
+    type MaxNumberOfPropertiesPerSchema = MaxNumberOfPropertiesPerSchema;
+    type MaxNumberOfEntitiesPerClass = MaxNumberOfEntitiesPerClass;
+    type MaxNumberOfCuratorsPerGroup = MaxNumberOfCuratorsPerGroup;
+    type MaxNumberOfOperationsDuringAtomicBatching = MaxNumberOfOperationsDuringAtomicBatching;
+    type VecMaxLengthConstraint = VecMaxLengthConstraint;
+    type TextMaxLengthConstraint = TextMaxLengthConstraint;
+    type HashedTextMaxLengthConstraint = HashedTextMaxLengthConstraint;
+    type IndividualEntitiesCreationLimit = IndividualEntitiesCreationLimit;
+}
+
 impl hiring::Trait for Runtime {
     type OpeningId = u64;
     type ApplicationId = u64;
@@ -454,9 +501,11 @@ impl storage::data_object_storage_registry::Trait for Runtime {
     type ContentIdExists = DataDirectory;
 }
 
+pub type MemberId = u64;
+
 impl membership::Trait for Runtime {
     type Event = Event;
-    type MemberId = u64;
+    type MemberId = MemberId;
     type PaidTermId = u64;
     type SubscriptionId = u64;
     type ActorId = ActorId;
@@ -472,6 +521,9 @@ impl forum::Trait for Runtime {
 // The storage working group instance alias.
 pub type StorageWorkingGroupInstance = working_group::Instance2;
 
+// The content directory working group instance alias.
+pub type ContentDirectoryWorkingGroupInstance = working_group::Instance3;
+
 parameter_types! {
     pub const MaxWorkerNumberLimit: u32 = 100;
 }
@@ -481,6 +533,11 @@ impl working_group::Trait<StorageWorkingGroupInstance> for Runtime {
     type MaxWorkerNumberLimit = MaxWorkerNumberLimit;
 }
 
+impl working_group::Trait<ContentDirectoryWorkingGroupInstance> for Runtime {
+    type Event = Event;
+    type MaxWorkerNumberLimit = MaxWorkerNumberLimit;
+}
+
 impl service_discovery::Trait for Runtime {
     type Event = Event;
 }
@@ -603,6 +660,7 @@ construct_runtime!(
         RecurringRewards: recurring_rewards::{Module, Call, Storage},
         Hiring: hiring::{Module, Call, Storage},
         ContentWorkingGroup: content_wg::{Module, Call, Storage, Event<T>, Config<T>},
+        ContentDirectory: content_directory::{Module, Call, Storage, Event<T>, Config<T>},
         // --- Storage
         DataObjectTypeRegistry: data_object_type_registry::{Module, Call, Storage, Event<T>, Config<T>},
         DataDirectory: data_directory::{Module, Call, Storage, Event<T>},
@@ -615,5 +673,6 @@ construct_runtime!(
         // --- Working groups
         // reserved for the future use: ForumWorkingGroup: working_group::<Instance1>::{Module, Call, Storage, Event<T>},
         StorageWorkingGroup: working_group::<Instance2>::{Module, Call, Storage, Config<T>, Event<T>},
+        ContentDirectoryWorkingGroup: working_group::<Instance3>::{Module, Call, Storage, Config<T>, Event<T>},
     }
 );