Browse Source

Merge branch 'storage_v2' into giza-protobuf-and-query-node

Leszek Wiesner 3 years ago
parent
commit
0335189f43

+ 1 - 0
.dockerignore

@@ -7,3 +7,4 @@ query-node/lib
 cli/
 cli/
 tests/
 tests/
 devops/
 devops/
+metadata-protobuf/lib

+ 5 - 4
.env

@@ -2,14 +2,14 @@ COMPOSE_PROJECT_NAME=joystream
 PROJECT_NAME=query_node
 PROJECT_NAME=query_node
 
 
 # We will use a single postgres service with multiple databases
 # We will use a single postgres service with multiple databases
-# The env variables below are by default used by all services and should be 
+# The env variables below are by default used by all services and should be
 # overriden in local env files
 # overriden in local env files
 # DB config
 # DB config
 INDEXER_DB_NAME=query_node_indexer
 INDEXER_DB_NAME=query_node_indexer
 DB_NAME=query_node_processor
 DB_NAME=query_node_processor
 DB_USER=postgres
 DB_USER=postgres
 DB_PASS=postgres
 DB_PASS=postgres
-DB_HOST=localhost
+DB_HOST=db
 DB_PORT=5432
 DB_PORT=5432
 DEBUG=index-builder:*
 DEBUG=index-builder:*
 TYPEORM_LOGGING=error
 TYPEORM_LOGGING=error
@@ -30,9 +30,10 @@ BLOCK_HEIGHT=0
 ###############################
 ###############################
 
 
 GRAPHQL_SERVER_PORT=4002
 GRAPHQL_SERVER_PORT=4002
-GRAPHQL_SERVER_HOST=localhost
+GRAPHQL_SERVER_HOST=graphql-server
+
 WARTHOG_APP_PORT=4002
 WARTHOG_APP_PORT=4002
-WARTHOG_APP_HOST=localhost
+WARTHOG_APP_HOST=hydra-indexer-gateway
 
 
 # Default configuration is to use the docker container
 # Default configuration is to use the docker container
 WS_PROVIDER_ENDPOINT_URI=ws://joystream-node:9944/
 WS_PROVIDER_ENDPOINT_URI=ws://joystream-node:9944/

+ 3 - 0
Cargo.lock

@@ -3828,6 +3828,9 @@ dependencies = [
  "frame-system",
  "frame-system",
  "pallet-balances",
  "pallet-balances",
  "pallet-common",
  "pallet-common",
+ "pallet-membership",
+ "pallet-randomness-collective-flip",
+ "pallet-storage",
  "pallet-timestamp",
  "pallet-timestamp",
  "parity-scale-codec",
  "parity-scale-codec",
  "serde",
  "serde",

+ 10 - 2
apps.Dockerfile

@@ -1,8 +1,17 @@
+FROM mikefarah/yq as manifest-maker
+# Change metadata.source in manifest file. It's not possible to override it via flag/env.
+USER root
+ARG WS_PROVIDER_ENDPOINT_URI
+COPY ./query-node/manifest.yml /joystream/qn-manifest.yml
+RUN yq e -i ".typegen.metadata.source = \"$WS_PROVIDER_ENDPOINT_URI\"" /joystream/qn-manifest.yml
+
 FROM --platform=linux/x86-64 node:14 as builder
 FROM --platform=linux/x86-64 node:14 as builder
 
 
 WORKDIR /joystream
 WORKDIR /joystream
 COPY . /joystream
 COPY . /joystream
-RUN  rm -fr /joystream/pioneer
+COPY --from=manifest-maker /joystream/qn-manifest.yml /joystream/query-node/manifest.yml
+
+RUN rm -fr /joystream/pioneer
 
 
 # Do not set NODE_ENV=production until after running yarn install
 # Do not set NODE_ENV=production until after running yarn install
 # to ensure dev dependencies are installed.
 # to ensure dev dependencies are installed.
@@ -11,7 +20,6 @@ RUN yarn --forzen-lockfile
 RUN yarn workspace @joystream/types build
 RUN yarn workspace @joystream/types build
 RUN yarn workspace @joystream/metadata-protobuf build
 RUN yarn workspace @joystream/metadata-protobuf build
 RUN yarn workspace query-node-root build
 RUN yarn workspace query-node-root build
-RUN yarn workspace storage-node build
 
 
 # Second stage to reduce image size, enable it when
 # Second stage to reduce image size, enable it when
 # all packages have correctly identified what is a devDependency and what is not.
 # all packages have correctly identified what is a devDependency and what is not.

+ 10 - 18
docker-compose.yml

@@ -45,8 +45,6 @@ services:
     env_file:
     env_file:
       # relative to working directory where docker-compose was run from
       # relative to working directory where docker-compose was run from
       - .env
       - .env
-    environment:
-      - WS_PROVIDER_ENDPOINT_URI=${WS_PROVIDER_ENDPOINT_URI}
     ports:
     ports:
       - '127.0.0.1:3001:3001'
       - '127.0.0.1:3001:3001'
     command: colossus --dev --ws-provider ${WS_PROVIDER_ENDPOINT_URI} --ipfs-host ipfs
     command: colossus --dev --ws-provider ${WS_PROVIDER_ENDPOINT_URI} --ipfs-host ipfs
@@ -74,12 +72,12 @@ services:
     build:
     build:
       context: .
       context: .
       dockerfile: apps.Dockerfile
       dockerfile: apps.Dockerfile
+      network: joystream_default
+      args:
+        - WS_PROVIDER_ENDPOINT_URI=${WS_PROVIDER_ENDPOINT_URI}
     env_file:
     env_file:
       # relative to working directory where docker-compose was run from
       # relative to working directory where docker-compose was run from
       - .env
       - .env
-    environment:
-      - DB_HOST=db
-      - DB_NAME=${DB_NAME}
     ports:
     ports:
       - "127.0.0.1:8081:${GRAPHQL_SERVER_PORT}"
       - "127.0.0.1:8081:${GRAPHQL_SERVER_PORT}"
     depends_on:
     depends_on:
@@ -92,9 +90,6 @@ services:
     env_file:
     env_file:
       # relative to working directory where docker-compose was run from
       # relative to working directory where docker-compose was run from
       - .env
       - .env
-    environment:
-      - DB_HOST=db
-      - DB_NAME=${DB_NAME}
     ports:
     ports:
       - "127.0.0.1:8081:${GRAPHQL_SERVER_PORT}"
       - "127.0.0.1:8081:${GRAPHQL_SERVER_PORT}"
     depends_on:
     depends_on:
@@ -112,15 +107,17 @@ services:
     build:
     build:
       context: .
       context: .
       dockerfile: apps.Dockerfile
       dockerfile: apps.Dockerfile
+      network: joystream_default
+      args:
+        - WS_PROVIDER_ENDPOINT_URI=${WS_PROVIDER_ENDPOINT_URI}
     env_file:
     env_file:
       # relative to working directory where docker-compose was run from
       # relative to working directory where docker-compose was run from
       - .env
       - .env
     environment:
     environment:
       - INDEXER_ENDPOINT_URL=http://hydra-indexer-gateway:${WARTHOG_APP_PORT}/graphql
       - INDEXER_ENDPOINT_URL=http://hydra-indexer-gateway:${WARTHOG_APP_PORT}/graphql
-      - TYPEORM_HOST=db
+      - TYPEORM_HOST=${DB_HOST}
       - TYPEORM_DATABASE=${DB_NAME}
       - TYPEORM_DATABASE=${DB_NAME}
-      - DEBUG=index-builder:*
-      - WS_PROVIDER_ENDPOINT_URI=ws://joystream-node:9944
+      - WS_PROVIDER_ENDPOINT_URI=${WS_PROVIDER_ENDPOINT_URI}
     volumes:
     volumes:
       - ./types/augment/all/defs.json:/joystream/query-node/mappings/lib/generated/types/typedefs.json
       - ./types/augment/all/defs.json:/joystream/query-node/mappings/lib/generated/types/typedefs.json
     depends_on:
     depends_on:
@@ -135,10 +132,8 @@ services:
       - .env
       - .env
     environment:
     environment:
       - INDEXER_ENDPOINT_URL=http://hydra-indexer-gateway:${WARTHOG_APP_PORT}/graphql
       - INDEXER_ENDPOINT_URL=http://hydra-indexer-gateway:${WARTHOG_APP_PORT}/graphql
-      - TYPEORM_HOST=db
+      - TYPEORM_HOST=${DB_HOST}
       - TYPEORM_DATABASE=${DB_NAME}
       - TYPEORM_DATABASE=${DB_NAME}
-      - DEBUG=index-builder:*
-      - WS_PROVIDER_ENDPOINT_URI=ws://joystream-node:9944
     depends_on:
     depends_on:
       - hydra-indexer-gateway
       - hydra-indexer-gateway
     volumes:
     volumes:
@@ -155,12 +150,9 @@ services:
       # relative to working directory where docker-compose was run from
       # relative to working directory where docker-compose was run from
       - .env
       - .env
     environment:
     environment:
-      - DB_HOST=db
       - DB_NAME=${INDEXER_DB_NAME}
       - DB_NAME=${INDEXER_DB_NAME}
       - INDEXER_WORKERS=5
       - INDEXER_WORKERS=5
       - REDIS_URI=redis://redis:6379/0
       - REDIS_URI=redis://redis:6379/0
-      - DEBUG=index-builder:*
-      - WS_PROVIDER_ENDPOINT_URI=${WS_PROVIDER_ENDPOINT_URI}
       - TYPES_JSON=types.json
       - TYPES_JSON=types.json
     depends_on:
     depends_on:
       - db
       - db
@@ -187,7 +179,7 @@ services:
       - PORT=${WARTHOG_APP_PORT}
       - PORT=${WARTHOG_APP_PORT}
       - DEBUG=*
       - DEBUG=*
     ports:
     ports:
-      - "127.0.0.1:4000:4002"
+      - "127.0.0.1:4000:${WARTHOG_APP_PORT}"
     depends_on:
     depends_on:
       - redis
       - redis
       - db
       - db

+ 1 - 1
metadata-protobuf/package.json

@@ -20,7 +20,7 @@
   "license": "MIT",
   "license": "MIT",
   "private": false,
   "private": false,
   "scripts": {
   "scripts": {
-    "build": "yarn compile && tsc",
+    "build": "yarn compile && rm -rf lib && tsc",
     "compile": "yarn ts-node ./scripts/compile.ts",
     "compile": "yarn ts-node ./scripts/compile.ts",
     "generate-doc": "./generate-md-doc.sh",
     "generate-doc": "./generate-md-doc.sh",
     "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' mocha --inline-diffs -r ts-node/register 'test/**/*.ts'",
     "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' mocha --inline-diffs -r ts-node/register 'test/**/*.ts'",

+ 0 - 1
query-node/build.sh

@@ -9,7 +9,6 @@ set -a
 . ../.env
 . ../.env
 set +a
 set +a
 
 
-# only use this when new Hydra releases and contents of `generated/` folder needs to be refreshed
 yarn clean
 yarn clean
 yarn codegen:noinstall
 yarn codegen:noinstall
 yarn typegen # if this fails try to run this command outside of yarn workspaces
 yarn typegen # if this fails try to run this command outside of yarn workspaces

+ 17 - 0
query-node/kill-img.sh

@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+set -e
+
+SCRIPT_PATH="$(dirname "${BASH_SOURCE[0]}")"
+cd $SCRIPT_PATH
+
+set -a
+. ../.env
+set +a
+
+# Only remove query-node related services
+docker-compose rm -vsf processor
+docker-compose rm -vsf graphql-server
+docker-compose rm -vsf indexer
+docker-compose rm -vsf hydra-indexer-gateway
+docker-compose rm -vsf redis
+docker-compose rm -vsf db

+ 4 - 4
query-node/package.json

@@ -28,10 +28,10 @@
     "typegen:configure": "NODE_URL=${NODE_URL:-ws://localhost:9000} envsub typegen.template.yml typegen.yml",
     "typegen:configure": "NODE_URL=${NODE_URL:-ws://localhost:9000} envsub typegen.template.yml typegen.yml",
     "typegen": "rm -rf ./mappings/generated && hydra-typegen typegen manifest.yml --debug",
     "typegen": "rm -rf ./mappings/generated && hydra-typegen typegen manifest.yml --debug",
     "mappings:build": "yarn workspace query-node-mappings build",
     "mappings:build": "yarn workspace query-node-mappings build",
-    "docker:build": "docker build . -f docker/Dockerfile.hydra -t hydra-kit:latest",
-    "docker:db:up": "(cd ../ && docker-compose up -d db)",
-    "docker:db:migrate": "docker run --env-file .env --env DB_HOST=db --env TYPEORM_HOST=db --network container:${PWD##*/}_db_1 hydra-kit:latest yarn db:migrate",
-    "docker:up": "docker-compose up -d"
+    "start:dev": "./start.sh",
+    "start": "./start-img.sh",
+    "kill:dev": "./kill.sh",
+    "kill": "./kill-img.sh"
   },
   },
   "author": "",
   "author": "",
   "license": "ISC",
   "license": "ISC",

+ 8 - 0
query-node/schemas/storage.graphql

@@ -144,6 +144,10 @@ type StorageBagStorageAssignment @entity {
 
 
   "Storage bucket that should store the bag"
   "Storage bucket that should store the bag"
   storageBucket: StorageBucket!
   storageBucket: StorageBucket!
+
+  # Relationship filtering workaround
+  storageBagId: ID
+  storageBucketId: ID
 }
 }
 
 
 type StorageBagDistributionAssignment @entity {
 type StorageBagDistributionAssignment @entity {
@@ -155,6 +159,10 @@ type StorageBagDistributionAssignment @entity {
 
 
   "Distribution bucket that should distribute the bag"
   "Distribution bucket that should distribute the bag"
   distributionBucket: DistributionBucket!
   distributionBucket: DistributionBucket!
+
+  # Relationship filtering workaround
+  storageBagId: ID
+  distributionBucketId: ID
 }
 }
 
 
 type StorageDataObject @entity {
 type StorageDataObject @entity {

+ 23 - 0
query-node/start-img.sh

@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+set -e
+
+SCRIPT_PATH="$(dirname "${BASH_SOURCE[0]}")"
+cd $SCRIPT_PATH
+
+set -a
+. ../.env
+set +a
+
+# Start the joystream-node first to allow fetching Olympia metadata during build (typegen)
+docker-compose up -d joystream-node
+
+# Bring up db
+docker-compose up -d db
+
+# Setup the db
+docker run --rm --env-file ../.env --network joystream_default joystream/apps workspace query-node-root db:prepare
+docker run --rm --env-file ../.env --network joystream_default joystream/apps workspace query-node-root db:migrate
+
+# Start processor and graphql server
+docker-compose up -d processor
+docker-compose up -d graphql-server

+ 8 - 2
query-node/start.sh

@@ -17,6 +17,9 @@ docker-compose up -d joystream-node
 # Bring up db
 # Bring up db
 docker-compose up -d db
 docker-compose up -d db
 
 
+# Override DB_HOST for db setup
+export DB_HOST=localhost
+
 # Make sure we use dev config for db migrations (prevents "Cannot create database..." and some other errors)
 # Make sure we use dev config for db migrations (prevents "Cannot create database..." and some other errors)
 yarn workspace query-node config:dev
 yarn workspace query-node config:dev
 
 
@@ -24,7 +27,10 @@ yarn workspace query-node config:dev
 yarn workspace query-node-root db:prepare
 yarn workspace query-node-root db:prepare
 yarn workspace query-node-root db:migrate
 yarn workspace query-node-root db:migrate
 
 
-docker-compose up -d graphql-server-mnt
+# Set DB_HOST back to docker-service one
+export DB_HOST=db
 
 
-# Starting up processor will bring up all services it depends on
+# Start processor and graphql server
 docker-compose up -d processor-mnt
 docker-compose up -d processor-mnt
+docker-compose up -d graphql-server-mnt
+

+ 1 - 11
runtime-modules/common/src/lib.rs

@@ -24,6 +24,7 @@ pub type ActorId<T> = <T as MembershipTypes>::ActorId;
 
 
 /// HTTP Url string
 /// HTTP Url string
 pub type Url = Vec<u8>;
 pub type Url = Vec<u8>;
+pub type AssetUrls = Vec<Url>;
 
 
 /// Generic trait for membership dependent pallets.
 /// Generic trait for membership dependent pallets.
 pub trait MembershipTypes: frame_system::Trait {
 pub trait MembershipTypes: frame_system::Trait {
@@ -65,17 +66,6 @@ pub trait StorageOwnership {
         + Ord
         + Ord
         + PartialEq;
         + PartialEq;
 
 
-    /// DAO id representation.
-    type DAOId: Parameter
-        + Member
-        + BaseArithmetic
-        + Codec
-        + Default
-        + Copy
-        + MaybeSerialize
-        + Ord
-        + PartialEq;
-
     /// Content id representation.
     /// Content id representation.
     type ContentId: Parameter + Member + Codec + Default + Copy + MaybeSerialize + Ord + PartialEq;
     type ContentId: Parameter + Member + Codec + Default + Copy + MaybeSerialize + Ord + PartialEq;
 
 

+ 7 - 13
runtime-modules/common/src/storage.rs

@@ -16,42 +16,36 @@ pub struct ContentParameters<ContentId, DataObjectTypeId> {
 // New owner type for storage object struct
 // New owner type for storage object struct
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Clone, Encode, Decode, PartialEq, Eq, Debug)]
 #[derive(Clone, Encode, Decode, PartialEq, Eq, Debug)]
-pub enum StorageObjectOwner<MemberId, ChannelId, DAOId> {
+pub enum StorageObjectOwner<MemberId, ChannelId> {
     Member(MemberId),
     Member(MemberId),
-    Channel(ChannelId), // acts through content directory module, where again DAOs can own channels for example
+    Channel(ChannelId), // acts through content directory module,
     #[allow(clippy::upper_case_acronyms)]
     #[allow(clippy::upper_case_acronyms)]
-    DAO(DAOId), // acts through upcoming `content_finance` module
-    Council,            // acts through proposal frame_system
+    Council, // acts through proposal frame_system
     WorkingGroup(WorkingGroup), // acts through new extrinsic in working group
     WorkingGroup(WorkingGroup), // acts through new extrinsic in working group
 }
 }
 
 
-impl<MemberId, ChannelId, DAOId> Default for StorageObjectOwner<MemberId, ChannelId, DAOId> {
-    fn default() -> Self {
-        Self::Council
-    }
-}
 // To be implemented by current storage data_directory runtime module.
 // To be implemented by current storage data_directory runtime module.
 // Defined in 'common' package
 // Defined in 'common' package
 pub trait StorageSystem<T: crate::StorageOwnership + crate::MembershipTypes> {
 pub trait StorageSystem<T: crate::StorageOwnership + crate::MembershipTypes> {
     fn atomically_add_content(
     fn atomically_add_content(
-        owner: StorageObjectOwner<T::MemberId, T::ChannelId, T::DAOId>,
+        owner: StorageObjectOwner<T::MemberId, T::ChannelId>,
         content_parameters: Vec<ContentParameters<T::ContentId, T::DataObjectTypeId>>,
         content_parameters: Vec<ContentParameters<T::ContentId, T::DataObjectTypeId>>,
     ) -> DispatchResult;
     ) -> DispatchResult;
 
 
     // Checks if given owner can add provided content to the storage frame_system
     // Checks if given owner can add provided content to the storage frame_system
     fn can_add_content(
     fn can_add_content(
-        owner: StorageObjectOwner<T::MemberId, T::ChannelId, T::DAOId>,
+        owner: StorageObjectOwner<T::MemberId, T::ChannelId>,
         content_parameters: Vec<ContentParameters<T::ContentId, T::DataObjectTypeId>>,
         content_parameters: Vec<ContentParameters<T::ContentId, T::DataObjectTypeId>>,
     ) -> DispatchResult;
     ) -> DispatchResult;
 
 
     fn atomically_remove_content(
     fn atomically_remove_content(
-        owner: &StorageObjectOwner<T::MemberId, T::ChannelId, T::DAOId>,
+        owner: &StorageObjectOwner<T::MemberId, T::ChannelId>,
         content_ids: &[T::ContentId],
         content_ids: &[T::ContentId],
     ) -> DispatchResult;
     ) -> DispatchResult;
 
 
     // Checks if given owner can remove content under given content ids from the storage frame_system
     // Checks if given owner can remove content under given content ids from the storage frame_system
     fn can_remove_content(
     fn can_remove_content(
-        owner: &StorageObjectOwner<T::MemberId, T::ChannelId, T::DAOId>,
+        owner: &StorageObjectOwner<T::MemberId, T::ChannelId>,
         content_ids: &[T::ContentId],
         content_ids: &[T::ContentId],
     ) -> DispatchResult;
     ) -> DispatchResult;
 }
 }

+ 10 - 2
runtime-modules/content/Cargo.toml

@@ -13,12 +13,17 @@ sp-arithmetic = { package = 'sp-arithmetic', default-features = false, git = 'ht
 codec = { package = 'parity-scale-codec', version = '1.3.4', default-features = false, features = ['derive'] }
 codec = { package = 'parity-scale-codec', version = '1.3.4', default-features = false, features = ['derive'] }
 serde = {version = '1.0.101', features = ['derive'], optional = true}
 serde = {version = '1.0.101', features = ['derive'], optional = true}
 common = { package = 'pallet-common', default-features = false, path = '../common'}
 common = { package = 'pallet-common', default-features = false, path = '../common'}
+storage = { package = 'pallet-storage', default-features = false, path = '../storage'}
+membership = { package = 'pallet-membership', default-features = false, path = '../membership'}
+balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = '2cd20966cc09b059817c3ebe12fc130cdd850d62'}
+
 
 
 [dev-dependencies]
 [dev-dependencies]
 sp-io = { package = 'sp-io', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = '2cd20966cc09b059817c3ebe12fc130cdd850d62'}
 sp-io = { package = 'sp-io', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = '2cd20966cc09b059817c3ebe12fc130cdd850d62'}
 sp-core = { package = 'sp-core', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = '2cd20966cc09b059817c3ebe12fc130cdd850d62'}
 sp-core = { package = 'sp-core', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = '2cd20966cc09b059817c3ebe12fc130cdd850d62'}
-balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = '2cd20966cc09b059817c3ebe12fc130cdd850d62'}
 pallet-timestamp = { package = 'pallet-timestamp', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = '2cd20966cc09b059817c3ebe12fc130cdd850d62'}
 pallet-timestamp = { package = 'pallet-timestamp', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = '2cd20966cc09b059817c3ebe12fc130cdd850d62'}
+randomness-collective-flip = { package = 'pallet-randomness-collective-flip', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = '2cd20966cc09b059817c3ebe12fc130cdd850d62'}
+
 
 
 [features]
 [features]
 default = ['std']
 default = ['std']
@@ -30,5 +35,8 @@ std = [
 	'sp-arithmetic/std',
 	'sp-arithmetic/std',
 	'codec/std',
 	'codec/std',
 	'serde',
 	'serde',
-	'common/std'
+	'common/std',
+	'storage/std',
+	'balances/std',
+	'membership/std',
 ]
 ]

+ 14 - 1
runtime-modules/content/src/errors.rs

@@ -62,6 +62,19 @@ decl_error! {
         VideoInSeason,
         VideoInSeason,
 
 
         /// Curators can only censor non-curator group owned channels
         /// Curators can only censor non-curator group owned channels
-        CannotCensoreCuratorGroupOwnedChannels
+        CannotCensoreCuratorGroupOwnedChannels,
+
+        /// No assets to be removed have been specified
+        NoAssetsSpecified,
+
+        /// Channel assets feasibility
+        InvalidAssetsProvided,
+
+        /// Channel Contains Video
+        ChannelContainsVideos,
+
+        /// Channel Contains Assets
+        ChannelContainsAssets,
+
     }
     }
 }
 }

File diff suppressed because it is too large
+ 325 - 217
runtime-modules/content/src/lib.rs


+ 3 - 4
runtime-modules/content/src/permissions/mod.rs

@@ -5,7 +5,6 @@ pub use curator_group::*;
 pub use crate::errors::*;
 pub use crate::errors::*;
 use crate::*;
 use crate::*;
 pub use codec::{Codec, Decode, Encode};
 pub use codec::{Codec, Decode, Encode};
-pub use common::MembershipTypes;
 use core::fmt::Debug;
 use core::fmt::Debug;
 use frame_support::{ensure, Parameter};
 use frame_support::{ensure, Parameter};
 #[cfg(feature = "std")]
 #[cfg(feature = "std")]
@@ -15,7 +14,7 @@ use sp_runtime::traits::{MaybeSerializeDeserialize, Member};
 // use frame_system::ensure_root;
 // use frame_system::ensure_root;
 
 
 /// Model of authentication manager.
 /// Model of authentication manager.
-pub trait ContentActorAuthenticator: frame_system::Trait + MembershipTypes {
+pub trait ContentActorAuthenticator: frame_system::Trait + membership::Trait {
     /// Curator identifier
     /// Curator identifier
     type CuratorId: Parameter
     type CuratorId: Parameter
         + Member
         + Member
@@ -132,7 +131,7 @@ pub fn ensure_actor_authorized_to_create_channel<T: Trait>(
 pub fn ensure_actor_authorized_to_update_channel<T: Trait>(
 pub fn ensure_actor_authorized_to_update_channel<T: Trait>(
     origin: T::Origin,
     origin: T::Origin,
     actor: &ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>,
     actor: &ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>,
-    owner: &ChannelOwner<T::MemberId, T::CuratorGroupId, T::DAOId>,
+    owner: &ChannelOwner<T::MemberId, T::CuratorGroupId>,
 ) -> DispatchResult {
 ) -> DispatchResult {
     // Only owner of a channel can update and delete channel assets.
     // Only owner of a channel can update and delete channel assets.
     // Lead can update and delete curator group owned channel assets.
     // Lead can update and delete curator group owned channel assets.
@@ -199,7 +198,7 @@ pub fn ensure_actor_authorized_to_set_featured_videos<T: Trait>(
 pub fn ensure_actor_authorized_to_censor<T: Trait>(
 pub fn ensure_actor_authorized_to_censor<T: Trait>(
     origin: T::Origin,
     origin: T::Origin,
     actor: &ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>,
     actor: &ContentActor<T::CuratorGroupId, T::CuratorId, T::MemberId>,
-    owner: &ChannelOwner<T::MemberId, T::CuratorGroupId, T::DAOId>,
+    owner: &ChannelOwner<T::MemberId, T::CuratorGroupId>,
 ) -> DispatchResult {
 ) -> DispatchResult {
     // Only lead and curators can censor channels and videos
     // Only lead and curators can censor channels and videos
     // Only lead can censor curator group owned channels and videos
     // Only lead can censor curator group owned channels and videos

+ 307 - 43
runtime-modules/content/src/tests/channels.rs

@@ -2,9 +2,273 @@
 
 
 use super::curators;
 use super::curators;
 use super::mock::*;
 use super::mock::*;
+use crate::sp_api_hidden_includes_decl_storage::hidden_include::traits::Currency;
 use crate::*;
 use crate::*;
 use frame_support::{assert_err, assert_ok};
 use frame_support::{assert_err, assert_ok};
 
 
+#[test]
+fn successful_channel_deletion() {
+    with_default_mock_builder(|| {
+        // Run to block one to see emitted events
+        run_to_block(1);
+
+        // create an account with enought balance
+        let _ = balances::Module::<Test>::deposit_creating(
+            &FIRST_MEMBER_ORIGIN,
+            <Test as balances::Trait>::Balance::from(100u32),
+        );
+
+        // 3 assets
+        let assets = NewAssets::<Test>::Upload(CreationUploadParameters {
+            object_creation_list: vec![
+                DataObjectCreationParameters {
+                    size: 3,
+                    ipfs_content_id: b"first".to_vec(),
+                },
+                DataObjectCreationParameters {
+                    size: 3,
+                    ipfs_content_id: b"second".to_vec(),
+                },
+                DataObjectCreationParameters {
+                    size: 3,
+                    ipfs_content_id: b"third".to_vec(),
+                },
+            ],
+            expected_data_size_fee: storage::DataObjectPerMegabyteFee::<Test>::get(),
+        });
+
+        let channel_id = NextChannelId::<Test>::get();
+
+        // create channel
+        create_channel_mock(
+            FIRST_MEMBER_ORIGIN,
+            ContentActor::Member(FIRST_MEMBER_ID),
+            ChannelCreationParametersRecord {
+                assets: assets,
+                meta: vec![],
+                reward_account: None,
+            },
+            Ok(()),
+        );
+
+        // attempt to delete channel with non zero assets
+        delete_channel_mock(
+            FIRST_MEMBER_ORIGIN,
+            ContentActor::Member(FIRST_MEMBER_ID),
+            channel_id,
+            Err(Error::<Test>::ChannelContainsAssets.into()),
+        );
+
+        // delete assets
+        let assets_to_delete = [0u64, 1u64, 2u64]
+            .iter()
+            .map(|&x| x)
+            .collect::<BTreeSet<_>>();
+
+        // delete channel assets
+        delete_channel_assets_mock(
+            FIRST_MEMBER_ORIGIN,
+            ContentActor::Member(FIRST_MEMBER_ID),
+            channel_id,
+            assets_to_delete,
+            Ok(()),
+        );
+
+        // successful deletion
+        delete_channel_mock(
+            FIRST_MEMBER_ORIGIN,
+            ContentActor::Member(FIRST_MEMBER_ID),
+            channel_id,
+            Ok(()),
+        );
+    })
+}
+
+#[test]
+fn successful_channel_assets_deletion() {
+    with_default_mock_builder(|| {
+        // Run to block one to see emitted events
+        run_to_block(1);
+
+        // create an account with enought balance
+        let _ = balances::Module::<Test>::deposit_creating(
+            &FIRST_MEMBER_ORIGIN,
+            <Test as balances::Trait>::Balance::from(100u32),
+        );
+
+        // 3 assets
+        let assets = NewAssets::<Test>::Upload(CreationUploadParameters {
+            object_creation_list: vec![
+                DataObjectCreationParameters {
+                    size: 3,
+                    ipfs_content_id: b"first".to_vec(),
+                },
+                DataObjectCreationParameters {
+                    size: 3,
+                    ipfs_content_id: b"second".to_vec(),
+                },
+                DataObjectCreationParameters {
+                    size: 3,
+                    ipfs_content_id: b"third".to_vec(),
+                },
+            ],
+            expected_data_size_fee: storage::DataObjectPerMegabyteFee::<Test>::get(),
+        });
+
+        let channel_id = NextChannelId::<Test>::get();
+        // create channel
+        create_channel_mock(
+            FIRST_MEMBER_ORIGIN,
+            ContentActor::Member(FIRST_MEMBER_ID),
+            ChannelCreationParametersRecord {
+                assets: assets,
+                meta: vec![],
+                reward_account: None,
+            },
+            Ok(()),
+        );
+
+        // delete assets
+        let assets_to_delete = [0u64, 1u64].iter().map(|&x| x).collect::<BTreeSet<_>>();
+
+        // delete channel assets
+        delete_channel_assets_mock(
+            FIRST_MEMBER_ORIGIN,
+            ContentActor::Member(FIRST_MEMBER_ID),
+            channel_id,
+            assets_to_delete,
+            Ok(()),
+        );
+    })
+}
+
+#[test]
+fn succesful_channel_update() {
+    with_default_mock_builder(|| {
+        // Run to block one to see emitted events
+        run_to_block(1);
+
+        // create an account with enought balance
+        let _ = balances::Module::<Test>::deposit_creating(
+            &FIRST_MEMBER_ORIGIN,
+            <Test as balances::Trait>::Balance::from(100u32),
+        );
+
+        // 2 + 1 assets to be uploaded
+        let assets = NewAssets::<Test>::Upload(CreationUploadParameters {
+            object_creation_list: vec![
+                DataObjectCreationParameters {
+                    size: 3,
+                    ipfs_content_id: b"first".to_vec(),
+                },
+                DataObjectCreationParameters {
+                    size: 3,
+                    ipfs_content_id: b"second".to_vec(),
+                },
+            ],
+            expected_data_size_fee: storage::DataObjectPerMegabyteFee::<Test>::get(),
+        });
+
+        let new_assets = NewAssets::<Test>::Upload(CreationUploadParameters {
+            object_creation_list: vec![
+                DataObjectCreationParameters {
+                    size: 3,
+                    ipfs_content_id: b"first".to_vec(),
+                },
+                DataObjectCreationParameters {
+                    size: 3,
+                    ipfs_content_id: b"second".to_vec(),
+                },
+            ],
+            expected_data_size_fee: storage::DataObjectPerMegabyteFee::<Test>::get(),
+        });
+
+        let channel_id = NextChannelId::<Test>::get();
+        // create channel
+        create_channel_mock(
+            FIRST_MEMBER_ORIGIN,
+            ContentActor::Member(FIRST_MEMBER_ID),
+            ChannelCreationParametersRecord {
+                assets: assets,
+                meta: vec![],
+                reward_account: None,
+            },
+            Ok(()),
+        );
+
+        // update channel
+        update_channel_mock(
+            FIRST_MEMBER_ORIGIN,
+            ContentActor::Member(FIRST_MEMBER_ID),
+            channel_id,
+            ChannelUpdateParametersRecord {
+                assets: Some(new_assets),
+                new_meta: None,
+                reward_account: None,
+            },
+            Ok(()),
+        );
+
+        // update with 0 assets
+        update_channel_mock(
+            FIRST_MEMBER_ORIGIN,
+            ContentActor::Member(FIRST_MEMBER_ID),
+            channel_id,
+            ChannelUpdateParametersRecord {
+                assets: None,
+                new_meta: None,
+                reward_account: None,
+            },
+            Ok(()),
+        );
+    })
+}
+
+#[test]
+fn succesful_channel_creation() {
+    with_default_mock_builder(|| {
+        // Run to block one to see emitted events
+        run_to_block(1);
+
+        // create an account with enought balance
+        let _ = balances::Module::<Test>::deposit_creating(
+            &FIRST_MEMBER_ORIGIN,
+            <Test as balances::Trait>::Balance::from(100u32),
+        );
+
+        // 3 assets to be uploaded
+        let assets = NewAssets::<Test>::Upload(CreationUploadParameters {
+            object_creation_list: vec![
+                DataObjectCreationParameters {
+                    size: 3,
+                    ipfs_content_id: b"first".to_vec(),
+                },
+                DataObjectCreationParameters {
+                    size: 3,
+                    ipfs_content_id: b"second".to_vec(),
+                },
+                DataObjectCreationParameters {
+                    size: 3,
+                    ipfs_content_id: b"third".to_vec(),
+                },
+            ],
+            expected_data_size_fee: storage::DataObjectPerMegabyteFee::<Test>::get(),
+        });
+
+        // create channel
+        create_channel_mock(
+            FIRST_MEMBER_ORIGIN,
+            ContentActor::Member(FIRST_MEMBER_ID),
+            ChannelCreationParametersRecord {
+                assets: assets,
+                meta: vec![],
+                reward_account: None,
+            },
+            Ok(()),
+        );
+    })
+}
+
 #[test]
 #[test]
 fn lead_cannot_create_channel() {
 fn lead_cannot_create_channel() {
     with_default_mock_builder(|| {
     with_default_mock_builder(|| {
@@ -12,8 +276,8 @@ fn lead_cannot_create_channel() {
             Content::create_channel(
             Content::create_channel(
                 Origin::signed(LEAD_ORIGIN),
                 Origin::signed(LEAD_ORIGIN),
                 ContentActor::Lead,
                 ContentActor::Lead,
-                ChannelCreationParameters {
-                    assets: vec![],
+                ChannelCreationParametersRecord {
+                    assets: NewAssets::<Test>::Urls(vec![]),
                     meta: vec![],
                     meta: vec![],
                     reward_account: None,
                     reward_account: None,
                 }
                 }
@@ -34,8 +298,8 @@ fn curator_owned_channels() {
             Content::create_channel(
             Content::create_channel(
                 Origin::signed(FIRST_CURATOR_ORIGIN),
                 Origin::signed(FIRST_CURATOR_ORIGIN),
                 ContentActor::Curator(FIRST_CURATOR_GROUP_ID, FIRST_CURATOR_ID),
                 ContentActor::Curator(FIRST_CURATOR_GROUP_ID, FIRST_CURATOR_ID),
-                ChannelCreationParameters {
-                    assets: vec![],
+                ChannelCreationParametersRecord {
+                    assets: NewAssets::<Test>::Urls(vec![]),
                     meta: vec![],
                     meta: vec![],
                     reward_account: None,
                     reward_account: None,
                 }
                 }
@@ -51,8 +315,8 @@ fn curator_owned_channels() {
             Content::create_channel(
             Content::create_channel(
                 Origin::signed(SECOND_CURATOR_ORIGIN),
                 Origin::signed(SECOND_CURATOR_ORIGIN),
                 ContentActor::Curator(FIRST_CURATOR_GROUP_ID, SECOND_CURATOR_ID),
                 ContentActor::Curator(FIRST_CURATOR_GROUP_ID, SECOND_CURATOR_ID),
-                ChannelCreationParameters {
-                    assets: vec![],
+                ChannelCreationParametersRecord {
+                    assets: NewAssets::<Test>::Urls(vec![]),
                     meta: vec![],
                     meta: vec![],
                     reward_account: None,
                     reward_account: None,
                 }
                 }
@@ -65,8 +329,8 @@ fn curator_owned_channels() {
             Content::create_channel(
             Content::create_channel(
                 Origin::signed(SECOND_CURATOR_ORIGIN),
                 Origin::signed(SECOND_CURATOR_ORIGIN),
                 ContentActor::Curator(FIRST_CURATOR_GROUP_ID, FIRST_CURATOR_ID),
                 ContentActor::Curator(FIRST_CURATOR_GROUP_ID, FIRST_CURATOR_ID),
-                ChannelCreationParameters {
-                    assets: vec![],
+                ChannelCreationParametersRecord {
+                    assets: NewAssets::<Test>::Urls(vec![]),
                     meta: vec![],
                     meta: vec![],
                     reward_account: None,
                     reward_account: None,
                 }
                 }
@@ -80,8 +344,8 @@ fn curator_owned_channels() {
         assert_ok!(Content::create_channel(
         assert_ok!(Content::create_channel(
             Origin::signed(FIRST_CURATOR_ORIGIN),
             Origin::signed(FIRST_CURATOR_ORIGIN),
             ContentActor::Curator(FIRST_CURATOR_GROUP_ID, FIRST_CURATOR_ID),
             ContentActor::Curator(FIRST_CURATOR_GROUP_ID, FIRST_CURATOR_ID),
-            ChannelCreationParameters {
-                assets: vec![],
+            ChannelCreationParametersRecord {
+                assets: NewAssets::<Test>::Urls(vec![]),
                 meta: vec![],
                 meta: vec![],
                 reward_account: None,
                 reward_account: None,
             }
             }
@@ -94,14 +358,14 @@ fn curator_owned_channels() {
                 channel_id,
                 channel_id,
                 ChannelRecord {
                 ChannelRecord {
                     owner: ChannelOwner::CuratorGroup(FIRST_CURATOR_GROUP_ID),
                     owner: ChannelOwner::CuratorGroup(FIRST_CURATOR_GROUP_ID),
-                    videos: vec![],
-                    playlists: vec![],
-                    series: vec![],
                     is_censored: false,
                     is_censored: false,
                     reward_account: None,
                     reward_account: None,
+                    deletion_prize_source_account_id: FIRST_CURATOR_ORIGIN,
+                    num_assets: 0,
+                    num_videos: 0,
                 },
                 },
-                ChannelCreationParameters {
-                    assets: vec![],
+                ChannelCreationParametersRecord {
+                    assets: NewAssets::<Test>::Urls(vec![]),
                     meta: vec![],
                     meta: vec![],
                     reward_account: None,
                     reward_account: None,
                 }
                 }
@@ -113,7 +377,7 @@ fn curator_owned_channels() {
             Origin::signed(FIRST_CURATOR_ORIGIN),
             Origin::signed(FIRST_CURATOR_ORIGIN),
             ContentActor::Curator(FIRST_CURATOR_GROUP_ID, FIRST_CURATOR_ID),
             ContentActor::Curator(FIRST_CURATOR_GROUP_ID, FIRST_CURATOR_ID),
             channel_id,
             channel_id,
-            ChannelUpdateParameters {
+            ChannelUpdateParametersRecord {
                 assets: None,
                 assets: None,
                 new_meta: None,
                 new_meta: None,
                 reward_account: None,
                 reward_account: None,
@@ -125,7 +389,7 @@ fn curator_owned_channels() {
             Origin::signed(LEAD_ORIGIN),
             Origin::signed(LEAD_ORIGIN),
             ContentActor::Lead,
             ContentActor::Lead,
             channel_id,
             channel_id,
-            ChannelUpdateParameters {
+            ChannelUpdateParametersRecord {
                 assets: None,
                 assets: None,
                 new_meta: None,
                 new_meta: None,
                 reward_account: None,
                 reward_account: None,
@@ -145,8 +409,8 @@ fn member_owned_channels() {
             Content::create_channel(
             Content::create_channel(
                 Origin::signed(UNKNOWN_ORIGIN),
                 Origin::signed(UNKNOWN_ORIGIN),
                 ContentActor::Member(MEMBERS_COUNT + 1),
                 ContentActor::Member(MEMBERS_COUNT + 1),
-                ChannelCreationParameters {
-                    assets: vec![],
+                ChannelCreationParametersRecord {
+                    assets: NewAssets::<Test>::Urls(vec![]),
                     meta: vec![],
                     meta: vec![],
                     reward_account: None,
                     reward_account: None,
                 }
                 }
@@ -160,8 +424,8 @@ fn member_owned_channels() {
         assert_ok!(Content::create_channel(
         assert_ok!(Content::create_channel(
             Origin::signed(FIRST_MEMBER_ORIGIN),
             Origin::signed(FIRST_MEMBER_ORIGIN),
             ContentActor::Member(FIRST_MEMBER_ID),
             ContentActor::Member(FIRST_MEMBER_ID),
-            ChannelCreationParameters {
-                assets: vec![],
+            ChannelCreationParametersRecord {
+                assets: NewAssets::<Test>::Urls(vec![]),
                 meta: vec![],
                 meta: vec![],
                 reward_account: None,
                 reward_account: None,
             }
             }
@@ -174,14 +438,14 @@ fn member_owned_channels() {
                 channel_id_1,
                 channel_id_1,
                 ChannelRecord {
                 ChannelRecord {
                     owner: ChannelOwner::Member(FIRST_MEMBER_ID),
                     owner: ChannelOwner::Member(FIRST_MEMBER_ID),
-                    videos: vec![],
-                    playlists: vec![],
-                    series: vec![],
                     is_censored: false,
                     is_censored: false,
                     reward_account: None,
                     reward_account: None,
+                    deletion_prize_source_account_id: FIRST_MEMBER_ORIGIN,
+                    num_assets: 0,
+                    num_videos: 0,
                 },
                 },
-                ChannelCreationParameters {
-                    assets: vec![],
+                ChannelCreationParametersRecord {
+                    assets: NewAssets::<Test>::Urls(vec![]),
                     meta: vec![],
                     meta: vec![],
                     reward_account: None,
                     reward_account: None,
                 }
                 }
@@ -194,8 +458,8 @@ fn member_owned_channels() {
         assert_ok!(Content::create_channel(
         assert_ok!(Content::create_channel(
             Origin::signed(SECOND_MEMBER_ORIGIN),
             Origin::signed(SECOND_MEMBER_ORIGIN),
             ContentActor::Member(SECOND_MEMBER_ID),
             ContentActor::Member(SECOND_MEMBER_ID),
-            ChannelCreationParameters {
-                assets: vec![],
+            ChannelCreationParametersRecord {
+                assets: NewAssets::<Test>::Urls(vec![]),
                 meta: vec![],
                 meta: vec![],
                 reward_account: None,
                 reward_account: None,
             }
             }
@@ -208,14 +472,14 @@ fn member_owned_channels() {
                 channel_id_2,
                 channel_id_2,
                 ChannelRecord {
                 ChannelRecord {
                     owner: ChannelOwner::Member(SECOND_MEMBER_ID),
                     owner: ChannelOwner::Member(SECOND_MEMBER_ID),
-                    videos: vec![],
-                    playlists: vec![],
-                    series: vec![],
                     is_censored: false,
                     is_censored: false,
                     reward_account: None,
                     reward_account: None,
+                    deletion_prize_source_account_id: SECOND_MEMBER_ORIGIN,
+                    num_assets: 0,
+                    num_videos: 0,
                 },
                 },
-                ChannelCreationParameters {
-                    assets: vec![],
+                ChannelCreationParametersRecord {
+                    assets: NewAssets::<Test>::Urls(vec![]),
                     meta: vec![],
                     meta: vec![],
                     reward_account: None,
                     reward_account: None,
                 }
                 }
@@ -227,7 +491,7 @@ fn member_owned_channels() {
             Origin::signed(FIRST_MEMBER_ORIGIN),
             Origin::signed(FIRST_MEMBER_ORIGIN),
             ContentActor::Member(FIRST_MEMBER_ID),
             ContentActor::Member(FIRST_MEMBER_ID),
             channel_id_1,
             channel_id_1,
-            ChannelUpdateParameters {
+            ChannelUpdateParametersRecord {
                 assets: None,
                 assets: None,
                 new_meta: None,
                 new_meta: None,
                 reward_account: None,
                 reward_account: None,
@@ -241,13 +505,13 @@ fn member_owned_channels() {
                 channel_id_1,
                 channel_id_1,
                 ChannelRecord {
                 ChannelRecord {
                     owner: ChannelOwner::Member(FIRST_MEMBER_ID),
                     owner: ChannelOwner::Member(FIRST_MEMBER_ID),
-                    videos: vec![],
-                    playlists: vec![],
-                    series: vec![],
                     is_censored: false,
                     is_censored: false,
                     reward_account: None,
                     reward_account: None,
+                    deletion_prize_source_account_id: FIRST_MEMBER_ORIGIN,
+                    num_assets: 0,
+                    num_videos: 0,
                 },
                 },
-                ChannelUpdateParameters {
+                ChannelUpdateParametersRecord {
                     assets: None,
                     assets: None,
                     new_meta: None,
                     new_meta: None,
                     reward_account: None,
                     reward_account: None,
@@ -261,7 +525,7 @@ fn member_owned_channels() {
                 Origin::signed(FIRST_MEMBER_ORIGIN),
                 Origin::signed(FIRST_MEMBER_ORIGIN),
                 ContentActor::Member(FIRST_MEMBER_ID),
                 ContentActor::Member(FIRST_MEMBER_ID),
                 channel_id_2,
                 channel_id_2,
-                ChannelUpdateParameters {
+                ChannelUpdateParametersRecord {
                     assets: None,
                     assets: None,
                     new_meta: None,
                     new_meta: None,
                     reward_account: None,
                     reward_account: None,
@@ -282,8 +546,8 @@ fn channel_censoring() {
         assert_ok!(Content::create_channel(
         assert_ok!(Content::create_channel(
             Origin::signed(FIRST_MEMBER_ORIGIN),
             Origin::signed(FIRST_MEMBER_ORIGIN),
             ContentActor::Member(FIRST_MEMBER_ID),
             ContentActor::Member(FIRST_MEMBER_ID),
-            ChannelCreationParameters {
-                assets: vec![],
+            ChannelCreationParametersRecord {
+                assets: NewAssets::<Test>::Urls(vec![]),
                 meta: vec![],
                 meta: vec![],
                 reward_account: None,
                 reward_account: None,
             }
             }
@@ -358,8 +622,8 @@ fn channel_censoring() {
         assert_ok!(Content::create_channel(
         assert_ok!(Content::create_channel(
             Origin::signed(FIRST_CURATOR_ORIGIN),
             Origin::signed(FIRST_CURATOR_ORIGIN),
             ContentActor::Curator(group_id, FIRST_CURATOR_ID),
             ContentActor::Curator(group_id, FIRST_CURATOR_ID),
-            ChannelCreationParameters {
-                assets: vec![],
+            ChannelCreationParametersRecord {
+                assets: NewAssets::<Test>::Urls(vec![]),
                 meta: vec![],
                 meta: vec![],
                 reward_account: None,
                 reward_account: None,
             }
             }

+ 364 - 30
runtime-modules/content/src/tests/mock.rs

@@ -2,25 +2,24 @@
 
 
 use crate::*;
 use crate::*;
 
 
+use frame_support::dispatch::{DispatchError, DispatchResult};
 use frame_support::traits::{OnFinalize, OnInitialize};
 use frame_support::traits::{OnFinalize, OnInitialize};
 use frame_support::{impl_outer_event, impl_outer_origin, parameter_types};
 use frame_support::{impl_outer_event, impl_outer_origin, parameter_types};
 use sp_core::H256;
 use sp_core::H256;
 use sp_runtime::{
 use sp_runtime::{
     testing::Header,
     testing::Header,
     traits::{BlakeTwo256, IdentityLookup},
     traits::{BlakeTwo256, IdentityLookup},
-    Perbill,
+    ModuleId, Perbill,
 };
 };
 
 
 use crate::ContentActorAuthenticator;
 use crate::ContentActorAuthenticator;
 use crate::Trait;
 use crate::Trait;
 use common::currency::GovernanceCurrency;
 use common::currency::GovernanceCurrency;
-use common::storage::StorageSystem;
 
 
 pub type CuratorId = <Test as ContentActorAuthenticator>::CuratorId;
 pub type CuratorId = <Test as ContentActorAuthenticator>::CuratorId;
 pub type CuratorGroupId = <Test as ContentActorAuthenticator>::CuratorGroupId;
 pub type CuratorGroupId = <Test as ContentActorAuthenticator>::CuratorGroupId;
 pub type MemberId = <Test as MembershipTypes>::MemberId;
 pub type MemberId = <Test as MembershipTypes>::MemberId;
 pub type ChannelId = <Test as StorageOwnership>::ChannelId;
 pub type ChannelId = <Test as StorageOwnership>::ChannelId;
-// pub type DAOId = <Test as StorageOwnership>::DAOId;
 
 
 /// Origins
 /// Origins
 
 
@@ -55,11 +54,21 @@ mod content {
     pub use crate::Event;
     pub use crate::Event;
 }
 }
 
 
+mod storage_mod {
+    pub use storage::Event;
+}
+
+mod membership_mod {
+    pub use membership::Event;
+}
+
 impl_outer_event! {
 impl_outer_event! {
     pub enum MetaEvent for Test {
     pub enum MetaEvent for Test {
         content<T>,
         content<T>,
         frame_system<T>,
         frame_system<T>,
         balances<T>,
         balances<T>,
+        membership_mod<T>,
+        storage_mod<T>,
     }
     }
 }
 }
 
 
@@ -116,7 +125,6 @@ impl common::MembershipTypes for Test {
 
 
 impl common::StorageOwnership for Test {
 impl common::StorageOwnership for Test {
     type ChannelId = u64;
     type ChannelId = u64;
-    type DAOId = u64;
     type ContentId = u64;
     type ContentId = u64;
     type DataObjectTypeId = u64;
     type DataObjectTypeId = u64;
 }
 }
@@ -139,6 +147,19 @@ impl GovernanceCurrency for Test {
     type Currency = balances::Module<Self>;
     type Currency = balances::Module<Self>;
 }
 }
 
 
+parameter_types! {
+    pub const ScreenedMemberMaxInitialBalance: u64 = 5000;
+}
+
+impl membership::Trait for Test {
+    type Event = MetaEvent;
+    type MemberId = u64;
+    type PaidTermId = u64;
+    type SubscriptionId = u64;
+    type ActorId = u64;
+    type ScreenedMemberMaxInitialBalance = ();
+}
+
 impl ContentActorAuthenticator for Test {
 impl ContentActorAuthenticator for Test {
     type CuratorId = u64;
     type CuratorId = u64;
     type CuratorGroupId = u64;
     type CuratorGroupId = u64;
@@ -166,39 +187,144 @@ impl ContentActorAuthenticator for Test {
     }
     }
 }
 }
 
 
-pub struct MockStorageSystem {}
+parameter_types! {
+    pub const MaxNumberOfDataObjectsPerBag: u64 = 4;
+    pub const MaxDistributionBucketFamilyNumber: u64 = 4;
+    pub const MaxDistributionBucketNumberPerFamily: u64 = 10;
+    pub const DataObjectDeletionPrize: u64 = 10;
+    pub const StorageModuleId: ModuleId = ModuleId(*b"mstorage"); // module storage
+    pub const BlacklistSizeLimit: u64 = 1;
+    pub const MaxNumberOfPendingInvitationsPerDistributionBucket: u64 = 1;
+    pub const StorageBucketsPerBagValueConstraint: storage::StorageBucketsPerBagValueConstraint =
+        storage::StorageBucketsPerBagValueConstraint {min: 3, max_min_diff: 7};
+    pub const InitialStorageBucketsNumberForDynamicBag: u64 = 3;
+    pub const MaxRandomIterationNumber: u64 = 3;
+    pub const DefaultMemberDynamicBagNumberOfStorageBuckets: u64 = 3;
+    pub const DefaultChannelDynamicBagNumberOfStorageBuckets: u64 = 4;
+    pub const DistributionBucketsPerBagValueConstraint: storage::DistributionBucketsPerBagValueConstraint =
+        storage::StorageBucketsPerBagValueConstraint {min: 3, max_min_diff: 7};
+    pub const MaxDataObjectSize: u64 = 400;
+}
 
 
-// Anyone can upload and delete without restriction
-impl StorageSystem<Test> for MockStorageSystem {
-    fn atomically_add_content(
-        _owner: StorageObjectOwner<Test>,
-        _content_parameters: Vec<ContentParameters<Test>>,
-    ) -> DispatchResult {
-        Ok(())
+pub const STORAGE_WG_LEADER_ACCOUNT_ID: u64 = 100001;
+pub const DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID: u64 = 100002;
+pub const DEFAULT_DISTRIBUTION_PROVIDER_ACCOUNT_ID: u64 = 100003;
+pub const DISTRIBUTION_WG_LEADER_ACCOUNT_ID: u64 = 100004;
+pub const DEFAULT_STORAGE_PROVIDER_ID: u64 = 10;
+pub const ANOTHER_STORAGE_PROVIDER_ID: u64 = 11;
+pub const DEFAULT_DISTRIBUTION_PROVIDER_ID: u64 = 12;
+pub const ANOTHER_DISTRIBUTION_PROVIDER_ID: u64 = 13;
+
+impl storage::Trait for Test {
+    type Event = MetaEvent;
+    type DataObjectId = u64;
+    type StorageBucketId = u64;
+    type DistributionBucketId = u64;
+    type DistributionBucketFamilyId = u64;
+    type DistributionBucketOperatorId = u64;
+    type ChannelId = u64;
+    type MaxNumberOfDataObjectsPerBag = MaxNumberOfDataObjectsPerBag;
+    type DataObjectDeletionPrize = DataObjectDeletionPrize;
+    type BlacklistSizeLimit = BlacklistSizeLimit;
+    type ModuleId = StorageModuleId;
+    type MemberOriginValidator = ();
+    type StorageBucketsPerBagValueConstraint = StorageBucketsPerBagValueConstraint;
+    type DefaultMemberDynamicBagNumberOfStorageBuckets =
+        DefaultMemberDynamicBagNumberOfStorageBuckets;
+    type DefaultChannelDynamicBagNumberOfStorageBuckets =
+        DefaultChannelDynamicBagNumberOfStorageBuckets;
+    type Randomness = CollectiveFlip;
+    type MaxRandomIterationNumber = MaxRandomIterationNumber;
+    type MaxDistributionBucketFamilyNumber = MaxDistributionBucketFamilyNumber;
+    type MaxDistributionBucketNumberPerFamily = MaxDistributionBucketNumberPerFamily;
+    type DistributionBucketsPerBagValueConstraint = DistributionBucketsPerBagValueConstraint;
+    type MaxNumberOfPendingInvitationsPerDistributionBucket =
+        MaxNumberOfPendingInvitationsPerDistributionBucket;
+    type ContentId = u64;
+    type MaxDataObjectSize = MaxDataObjectSize;
+
+    fn ensure_storage_working_group_leader_origin(origin: Self::Origin) -> DispatchResult {
+        let account_id = ensure_signed(origin)?;
+
+        if account_id != STORAGE_WG_LEADER_ACCOUNT_ID {
+            Err(DispatchError::BadOrigin)
+        } else {
+            Ok(())
+        }
+    }
+
+    fn ensure_storage_worker_origin(origin: Self::Origin, _: u64) -> DispatchResult {
+        let account_id = ensure_signed(origin)?;
+
+        if account_id != DEFAULT_STORAGE_PROVIDER_ACCOUNT_ID {
+            Err(DispatchError::BadOrigin)
+        } else {
+            Ok(())
+        }
+    }
+
+    fn ensure_storage_worker_exists(worker_id: &u64) -> DispatchResult {
+        let allowed_storage_providers =
+            vec![DEFAULT_STORAGE_PROVIDER_ID, ANOTHER_STORAGE_PROVIDER_ID];
+
+        if !allowed_storage_providers.contains(worker_id) {
+            Err(DispatchError::Other("Invalid worker"))
+        } else {
+            Ok(())
+        }
+    }
+
+    fn ensure_distribution_working_group_leader_origin(origin: Self::Origin) -> DispatchResult {
+        let account_id = ensure_signed(origin)?;
+
+        if account_id != DISTRIBUTION_WG_LEADER_ACCOUNT_ID {
+            Err(DispatchError::BadOrigin)
+        } else {
+            Ok(())
+        }
     }
     }
 
 
-    fn can_add_content(
-        _owner: StorageObjectOwner<Test>,
-        _content_parameters: Vec<ContentParameters<Test>>,
-    ) -> DispatchResult {
-        Ok(())
+    fn ensure_distribution_worker_origin(origin: Self::Origin, _: u64) -> DispatchResult {
+        let account_id = ensure_signed(origin)?;
+
+        if account_id != DEFAULT_DISTRIBUTION_PROVIDER_ACCOUNT_ID {
+            Err(DispatchError::BadOrigin)
+        } else {
+            Ok(())
+        }
     }
     }
 
 
-    fn atomically_remove_content(
-        _owner: &StorageObjectOwner<Test>,
-        _content_ids: &[u64],
-    ) -> DispatchResult {
-        Ok(())
+    fn ensure_distribution_worker_exists(worker_id: &u64) -> DispatchResult {
+        let allowed_providers = vec![
+            DEFAULT_DISTRIBUTION_PROVIDER_ID,
+            ANOTHER_DISTRIBUTION_PROVIDER_ID,
+        ];
+
+        if !allowed_providers.contains(worker_id) {
+            Err(DispatchError::Other("Invalid worker"))
+        } else {
+            Ok(())
+        }
     }
     }
+}
 
 
-    fn can_remove_content(
-        _owner: &StorageObjectOwner<Test>,
-        _content_ids: &[u64],
-    ) -> DispatchResult {
-        Ok(())
+pub const DEFAULT_MEMBER_ID: u64 = 100;
+pub const DEFAULT_MEMBER_ACCOUNT_ID: u64 = 101;
+
+impl common::origin::ActorOriginValidator<Origin, u64, u64> for () {
+    fn ensure_actor_origin(origin: Origin, member_id: u64) -> Result<u64, &'static str> {
+        let signed_account_id = frame_system::ensure_signed(origin)?;
+
+        if signed_account_id == DEFAULT_MEMBER_ACCOUNT_ID && member_id == DEFAULT_MEMBER_ID {
+            Ok(signed_account_id)
+        } else {
+            Err(DispatchError::BadOrigin.into())
+        }
     }
     }
 }
 }
 
 
+// Anyone can upload and delete without restriction
+
 parameter_types! {
 parameter_types! {
     pub const MaxNumberOfCuratorsPerGroup: u32 = 10;
     pub const MaxNumberOfCuratorsPerGroup: u32 = 10;
     pub const ChannelOwnershipPaymentEscrowId: [u8; 8] = *b"12345678";
     pub const ChannelOwnershipPaymentEscrowId: [u8; 8] = *b"12345678";
@@ -234,9 +360,6 @@ impl Trait for Test {
 
 
     /// The maximum number of curators per group constraint
     /// The maximum number of curators per group constraint
     type MaxNumberOfCuratorsPerGroup = MaxNumberOfCuratorsPerGroup;
     type MaxNumberOfCuratorsPerGroup = MaxNumberOfCuratorsPerGroup;
-
-    // Type that handles asset uploads to storage frame_system
-    type StorageSystem = MockStorageSystem;
 }
 }
 
 
 pub type System = frame_system::Module<Test>;
 pub type System = frame_system::Module<Test>;
@@ -307,3 +430,214 @@ pub fn run_to_block(n: u64) {
         <System as OnInitialize<u64>>::on_initialize(System::block_number());
         <System as OnInitialize<u64>>::on_initialize(System::block_number());
     }
     }
 }
 }
+
+pub type CollectiveFlip = randomness_collective_flip::Module<Test>;
+
+pub fn create_channel_mock(
+    sender: u64,
+    actor: ContentActor<CuratorGroupId, CuratorId, MemberId>,
+    params: ChannelCreationParameters<Test>,
+    result: DispatchResult,
+) {
+    let channel_id = Content::next_channel_id();
+
+    assert_eq!(
+        Content::create_channel(Origin::signed(sender), actor.clone(), params.clone()),
+        result.clone(),
+    );
+
+    if result.is_ok() {
+        let num_assets = match params.assets.clone() {
+            NewAssets::<Test>::Urls(v) => v.len() as u64,
+            NewAssets::<Test>::Upload(c) => c.object_creation_list.len() as u64,
+        };
+        let owner = Content::actor_to_channel_owner(&actor).unwrap();
+
+        assert_eq!(
+            System::events().last().unwrap().event,
+            MetaEvent::content(RawEvent::ChannelCreated(
+                actor.clone(),
+                channel_id,
+                ChannelRecord {
+                    owner: owner,
+                    is_censored: false,
+                    reward_account: params.reward_account,
+                    deletion_prize_source_account_id: sender,
+                    num_assets: num_assets,
+                    num_videos: 0,
+                },
+                params.clone(),
+            ))
+        );
+    }
+}
+
+pub fn update_channel_mock(
+    sender: u64,
+    actor: ContentActor<CuratorGroupId, CuratorId, MemberId>,
+    channel_id: ChannelId,
+    params: ChannelUpdateParameters<Test>,
+    result: DispatchResult,
+) {
+    let channel_pre = ChannelById::<Test>::get(channel_id.clone());
+
+    assert_eq!(
+        Content::update_channel(
+            Origin::signed(sender),
+            actor.clone(),
+            channel_id.clone(),
+            params.clone()
+        ),
+        result.clone(),
+    );
+
+    if result.is_ok() {
+        let maybe_num_assets = params.assets.clone().map_or(None, |assets| match assets {
+            NewAssets::<Test>::Urls(v) => Some(v.len() as u64),
+            NewAssets::<Test>::Upload(c) => Some(c.object_creation_list.len() as u64),
+        });
+        assert_eq!(
+            System::events().last().unwrap().event,
+            MetaEvent::content(RawEvent::ChannelUpdated(
+                actor.clone(),
+                channel_id,
+                ChannelRecord {
+                    owner: channel_pre.owner.clone(),
+                    is_censored: channel_pre.is_censored,
+                    reward_account: channel_pre.reward_account.clone(),
+                    deletion_prize_source_account_id: sender,
+                    num_assets: channel_pre.num_assets + maybe_num_assets.unwrap_or(0),
+                    num_videos: channel_pre.num_videos,
+                },
+                params.clone(),
+            ))
+        );
+    }
+}
+
+pub fn delete_channel_assets_mock(
+    sender: u64,
+    actor: ContentActor<CuratorGroupId, CuratorId, MemberId>,
+    channel_id: ChannelId,
+    assets: BTreeSet<<Test as storage::Trait>::DataObjectId>,
+    result: DispatchResult,
+) {
+    let channel_pre = ChannelById::<Test>::get(channel_id.clone());
+
+    assert_eq!(
+        Content::remove_channel_assets(
+            Origin::signed(sender),
+            actor.clone(),
+            channel_id.clone(),
+            assets.clone(),
+        ),
+        result.clone(),
+    );
+
+    if result.is_ok() {
+        let num_assets_removed = assets.len();
+        assert_eq!(
+            System::events().last().unwrap().event,
+            MetaEvent::content(RawEvent::ChannelAssetsRemoved(
+                actor.clone(),
+                channel_id,
+                assets.clone(),
+                ChannelRecord {
+                    owner: channel_pre.owner.clone(),
+                    is_censored: channel_pre.is_censored,
+                    reward_account: channel_pre.reward_account.clone(),
+                    deletion_prize_source_account_id: sender,
+                    num_assets: channel_pre.num_assets - (num_assets_removed as u64),
+                    num_videos: channel_pre.num_videos,
+                },
+            ))
+        );
+    }
+}
+
+pub fn delete_channel_mock(
+    sender: u64,
+    actor: ContentActor<CuratorGroupId, CuratorId, MemberId>,
+    channel_id: ChannelId,
+    result: DispatchResult,
+) {
+    assert_eq!(
+        Content::delete_channel(Origin::signed(sender), actor.clone(), channel_id.clone()),
+        result.clone(),
+    );
+
+    if result.is_ok() {
+        assert_eq!(
+            System::events().last().unwrap().event,
+            MetaEvent::content(RawEvent::ChannelDeleted(actor.clone(), channel_id))
+        )
+    }
+}
+
+pub fn create_video_mock(
+    sender: u64,
+    actor: ContentActor<CuratorGroupId, CuratorId, MemberId>,
+    channel_id: ChannelId,
+    params: VideoCreationParameters<Test>,
+    result: DispatchResult,
+) {
+    let video_id = Content::next_video_id();
+    let num_videos_pre = Content::channel_by_id(channel_id).num_videos;
+
+    assert_eq!(
+        Content::create_video(
+            Origin::signed(sender),
+            actor.clone(),
+            channel_id.clone(),
+            params.clone()
+        ),
+        result.clone(),
+    );
+
+    if result.is_ok() {
+        assert_eq!(
+            System::events().last().unwrap().event,
+            MetaEvent::content(RawEvent::VideoCreated(
+                actor.clone(),
+                channel_id,
+                video_id,
+                params.clone(),
+            ))
+        );
+        assert_eq!(
+            num_videos_pre + 1,
+            Content::channel_by_id(channel_id).num_videos,
+        );
+    }
+}
+pub fn update_video_mock(
+    sender: u64,
+    actor: ContentActor<CuratorGroupId, CuratorId, MemberId>,
+    video_id: <Test as Trait>::VideoId,
+    params: VideoUpdateParameters<Test>,
+    result: DispatchResult,
+) {
+    // let channel_id = Content::video_by_id(video_id.clone()).in_channel;
+    // let num_videos_pre = Content::channel_by_id(channel_id).num_videos;
+
+    assert_eq!(
+        Content::update_video(
+            Origin::signed(sender),
+            actor.clone(),
+            video_id.clone(),
+            params.clone()
+        ),
+        result.clone(),
+    );
+
+    if result.is_ok() {
+        assert_eq!(
+            System::events().last().unwrap().event,
+            MetaEvent::content(RawEvent::VideoUpdated(
+                actor.clone(),
+                video_id,
+                params.clone(),
+            ))
+        );
+    }
+}

+ 148 - 17
runtime-modules/content/src/tests/videos.rs

@@ -2,6 +2,7 @@
 
 
 use super::curators;
 use super::curators;
 use super::mock::*;
 use super::mock::*;
+use crate::sp_api_hidden_includes_decl_storage::hidden_include::traits::Currency;
 use crate::*;
 use crate::*;
 use frame_support::{assert_err, assert_ok};
 use frame_support::{assert_err, assert_ok};
 
 
@@ -12,8 +13,8 @@ fn create_member_channel() -> ChannelId {
     assert_ok!(Content::create_channel(
     assert_ok!(Content::create_channel(
         Origin::signed(FIRST_MEMBER_ORIGIN),
         Origin::signed(FIRST_MEMBER_ORIGIN),
         ContentActor::Member(FIRST_MEMBER_ID),
         ContentActor::Member(FIRST_MEMBER_ID),
-        ChannelCreationParameters {
-            assets: vec![],
+        ChannelCreationParametersRecord {
+            assets: NewAssets::<Test>::Urls(vec![]),
             meta: vec![],
             meta: vec![],
             reward_account: None,
             reward_account: None,
         }
         }
@@ -22,6 +23,136 @@ fn create_member_channel() -> ChannelId {
     channel_id
     channel_id
 }
 }
 
 
+#[test]
+fn video_creation_successful() {
+    with_default_mock_builder(|| {
+        run_to_block(1);
+
+        // depositi initial balance
+        let _ = balances::Module::<Test>::deposit_creating(
+            &FIRST_MEMBER_ORIGIN,
+            <Test as balances::Trait>::Balance::from(100u32),
+        );
+
+        let channel_id = NextChannelId::<Test>::get();
+
+        create_channel_mock(
+            FIRST_MEMBER_ORIGIN,
+            ContentActor::Member(FIRST_MEMBER_ID),
+            ChannelCreationParametersRecord {
+                assets: NewAssets::<Test>::Urls(vec![]),
+                meta: vec![],
+                reward_account: None,
+            },
+            Ok(()),
+        );
+
+        let params = VideoCreationParametersRecord {
+            assets: NewAssets::<Test>::Upload(CreationUploadParameters {
+                object_creation_list: vec![
+                    DataObjectCreationParameters {
+                        size: 3,
+                        ipfs_content_id: b"first".to_vec(),
+                    },
+                    DataObjectCreationParameters {
+                        size: 3,
+                        ipfs_content_id: b"second".to_vec(),
+                    },
+                    DataObjectCreationParameters {
+                        size: 3,
+                        ipfs_content_id: b"third".to_vec(),
+                    },
+                ],
+                expected_data_size_fee: storage::DataObjectPerMegabyteFee::<Test>::get(),
+            }),
+            meta: b"test".to_vec(),
+        };
+
+        create_video_mock(
+            FIRST_MEMBER_ORIGIN,
+            ContentActor::Member(FIRST_MEMBER_ID),
+            channel_id,
+            params,
+            Ok(()),
+        )
+    })
+}
+
+#[test]
+fn video_update_successful() {
+    with_default_mock_builder(|| {
+        run_to_block(1);
+
+        let _ = balances::Module::<Test>::deposit_creating(
+            &FIRST_MEMBER_ORIGIN,
+            <Test as balances::Trait>::Balance::from(100u32),
+        );
+
+        let channel_id = NextChannelId::<Test>::get();
+
+        create_channel_mock(
+            FIRST_MEMBER_ORIGIN,
+            ContentActor::Member(FIRST_MEMBER_ID),
+            ChannelCreationParametersRecord {
+                assets: NewAssets::<Test>::Urls(vec![]),
+                meta: vec![],
+                reward_account: None,
+            },
+            Ok(()),
+        );
+
+        let params = VideoCreationParametersRecord {
+            assets: NewAssets::<Test>::Upload(CreationUploadParameters {
+                object_creation_list: vec![
+                    DataObjectCreationParameters {
+                        size: 3,
+                        ipfs_content_id: b"first".to_vec(),
+                    },
+                    DataObjectCreationParameters {
+                        size: 3,
+                        ipfs_content_id: b"second".to_vec(),
+                    },
+                    DataObjectCreationParameters {
+                        size: 3,
+                        ipfs_content_id: b"third".to_vec(),
+                    },
+                ],
+                expected_data_size_fee: storage::DataObjectPerMegabyteFee::<Test>::get(),
+            }),
+            meta: b"test".to_vec(),
+        };
+
+        let video_id = Content::next_video_id();
+
+        create_video_mock(
+            FIRST_MEMBER_ORIGIN,
+            ContentActor::Member(FIRST_MEMBER_ID),
+            channel_id,
+            params,
+            Ok(()),
+        );
+
+        let update_params = VideoUpdateParametersRecord {
+            assets: Some(NewAssets::<Test>::Upload(CreationUploadParameters {
+                object_creation_list: vec![DataObjectCreationParameters {
+                    size: 3,
+                    ipfs_content_id: b"first".to_vec(),
+                }],
+                expected_data_size_fee: storage::DataObjectPerMegabyteFee::<Test>::get(),
+            })),
+            new_meta: None,
+        };
+
+        update_video_mock(
+            FIRST_MEMBER_ORIGIN,
+            ContentActor::Member(FIRST_MEMBER_ID),
+            video_id,
+            update_params,
+            Ok(()),
+        );
+    })
+}
+
 #[test]
 #[test]
 fn member_can_create_videos() {
 fn member_can_create_videos() {
     with_default_mock_builder(|| {
     with_default_mock_builder(|| {
@@ -34,8 +165,8 @@ fn member_can_create_videos() {
             Origin::signed(FIRST_MEMBER_ORIGIN),
             Origin::signed(FIRST_MEMBER_ORIGIN),
             ContentActor::Member(FIRST_MEMBER_ID),
             ContentActor::Member(FIRST_MEMBER_ID),
             channel_id,
             channel_id,
-            VideoCreationParameters {
-                assets: vec![NewAsset::Urls(vec![b"https://somewhere.com/".to_vec()])],
+            VideoCreationParametersRecord {
+                assets: NewAssets::<Test>::Urls(vec![vec![b"https://somewhere.com/".to_vec()]]),
                 meta: b"metablob".to_vec(),
                 meta: b"metablob".to_vec(),
             }
             }
         ));
         ));
@@ -46,8 +177,8 @@ fn member_can_create_videos() {
                 ContentActor::Member(FIRST_MEMBER_ID),
                 ContentActor::Member(FIRST_MEMBER_ID),
                 channel_id,
                 channel_id,
                 video_id,
                 video_id,
-                VideoCreationParameters {
-                    assets: vec![NewAsset::Urls(vec![b"https://somewhere.com/".to_vec()])],
+                VideoCreationParametersRecord {
+                    assets: NewAssets::<Test>::Urls(vec![vec![b"https://somewhere.com/".to_vec()]]),
                     meta: b"metablob".to_vec(),
                     meta: b"metablob".to_vec(),
                 }
                 }
             ))
             ))
@@ -62,10 +193,10 @@ fn member_can_create_videos() {
             Origin::signed(FIRST_MEMBER_ORIGIN),
             Origin::signed(FIRST_MEMBER_ORIGIN),
             ContentActor::Member(FIRST_MEMBER_ID),
             ContentActor::Member(FIRST_MEMBER_ID),
             video_id,
             video_id,
-            VideoUpdateParameters {
-                assets: Some(vec![NewAsset::Urls(vec![
+            VideoUpdateParametersRecord {
+                assets: Some(NewAssets::<Test>::Urls(vec![vec![
                     b"https://somewhere-else.com/".to_vec()
                     b"https://somewhere-else.com/".to_vec()
-                ])]),
+                ]])),
                 new_meta: Some(b"newmetablob".to_vec()),
                 new_meta: Some(b"newmetablob".to_vec()),
             }
             }
         ));
         ));
@@ -75,10 +206,10 @@ fn member_can_create_videos() {
             MetaEvent::content(RawEvent::VideoUpdated(
             MetaEvent::content(RawEvent::VideoUpdated(
                 ContentActor::Member(FIRST_MEMBER_ID),
                 ContentActor::Member(FIRST_MEMBER_ID),
                 video_id,
                 video_id,
-                VideoUpdateParameters {
-                    assets: Some(vec![NewAsset::Urls(vec![
+                VideoUpdateParametersRecord {
+                    assets: Some(NewAssets::<Test>::Urls(vec![vec![
                         b"https://somewhere-else.com/".to_vec()
                         b"https://somewhere-else.com/".to_vec()
-                    ])]),
+                    ]])),
                     new_meta: Some(b"newmetablob".to_vec()),
                     new_meta: Some(b"newmetablob".to_vec()),
                 }
                 }
             ))
             ))
@@ -90,8 +221,8 @@ fn member_can_create_videos() {
                 Origin::signed(SECOND_MEMBER_ORIGIN),
                 Origin::signed(SECOND_MEMBER_ORIGIN),
                 ContentActor::Member(SECOND_MEMBER_ID),
                 ContentActor::Member(SECOND_MEMBER_ID),
                 channel_id,
                 channel_id,
-                VideoCreationParameters {
-                    assets: vec![],
+                VideoCreationParametersRecord {
+                    assets: NewAssets::<Test>::Urls(vec![]),
                     meta: vec![],
                     meta: vec![],
                 }
                 }
             ),
             ),
@@ -104,7 +235,7 @@ fn member_can_create_videos() {
                 Origin::signed(SECOND_MEMBER_ORIGIN),
                 Origin::signed(SECOND_MEMBER_ORIGIN),
                 ContentActor::Member(SECOND_MEMBER_ID),
                 ContentActor::Member(SECOND_MEMBER_ID),
                 video_id,
                 video_id,
-                VideoUpdateParameters {
+                VideoUpdateParametersRecord {
                     assets: None,
                     assets: None,
                     new_meta: None,
                     new_meta: None,
                 }
                 }
@@ -151,8 +282,8 @@ fn curators_can_censor_videos() {
             Origin::signed(FIRST_MEMBER_ORIGIN),
             Origin::signed(FIRST_MEMBER_ORIGIN),
             ContentActor::Member(FIRST_MEMBER_ID),
             ContentActor::Member(FIRST_MEMBER_ID),
             channel_id,
             channel_id,
-            VideoCreationParameters {
-                assets: vec![NewAsset::Urls(vec![b"https://somewhere.com/".to_vec()])],
+            VideoCreationParametersRecord {
+                assets: NewAssets::<Test>::Urls(vec![vec![b"https://somewhere.com/".to_vec()]]),
                 meta: b"metablob".to_vec(),
                 meta: b"metablob".to_vec(),
             }
             }
         ));
         ));

+ 9 - 3
runtime-modules/storage/src/lib.rs

@@ -118,6 +118,8 @@
 
 
 // Internal Substrate warning (decl_event).
 // Internal Substrate warning (decl_event).
 #![allow(clippy::unused_unit)]
 #![allow(clippy::unused_unit)]
+// needed for step iteration over DataObjectId range
+#![feature(step_trait)]
 
 
 #[cfg(test)]
 #[cfg(test)]
 mod tests;
 mod tests;
@@ -216,6 +218,9 @@ pub trait Trait: frame_system::Trait + balances::Trait + membership::Trait {
     /// Storage event type.
     /// Storage event type.
     type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
     type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
 
 
+    /// Content id representation.
+    type ContentId: Parameter + Member + Codec + Default + Copy + MaybeSerialize + Ord + PartialEq;
+
     /// Data object ID type.
     /// Data object ID type.
     type DataObjectId: Parameter
     type DataObjectId: Parameter
         + Member
         + Member
@@ -224,7 +229,8 @@ pub trait Trait: frame_system::Trait + balances::Trait + membership::Trait {
         + Default
         + Default
         + Copy
         + Copy
         + MaybeSerialize
         + MaybeSerialize
-        + PartialEq;
+        + PartialEq
+        + iter::Step; // needed for iteration
 
 
     /// Storage bucket ID type.
     /// Storage bucket ID type.
     type StorageBucketId: Parameter
     type StorageBucketId: Parameter
@@ -462,7 +468,7 @@ pub type BalanceOf<T> = <T as balances::Trait>::Balance;
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
 #[derive(Encode, Decode, Default, Clone, PartialEq, Eq, Debug)]
 pub struct DataObject<Balance> {
 pub struct DataObject<Balance> {
-    /// Defines whether the data object was accepted by a liaison.
+    /// Defines whether the data object was accepted by a liason.
     pub accepted: bool,
     pub accepted: bool,
 
 
     /// A reward for the data object deletion.
     /// A reward for the data object deletion.
@@ -932,7 +938,7 @@ decl_storage! {
         /// "Max objects size for a storage bucket voucher" number limit.
         /// "Max objects size for a storage bucket voucher" number limit.
         pub VoucherMaxObjectsSizeLimit get (fn voucher_max_objects_size_limit): u64;
         pub VoucherMaxObjectsSizeLimit get (fn voucher_max_objects_size_limit): u64;
 
 
-        /// "Max objects number for a storage bucket voucher" number limit.
+        /// "Max objects number for a storage  bucket voucher" number limit.
         pub VoucherMaxObjectsNumberLimit get (fn voucher_max_objects_number_limit): u64;
         pub VoucherMaxObjectsNumberLimit get (fn voucher_max_objects_number_limit): u64;
 
 
         /// DynamicBagCreationPolicy by bag type storage map.
         /// DynamicBagCreationPolicy by bag type storage map.

+ 1 - 0
runtime-modules/storage/src/tests/mocks.rs

@@ -103,6 +103,7 @@ impl crate::Trait for Test {
     type MaxNumberOfPendingInvitationsPerDistributionBucket =
     type MaxNumberOfPendingInvitationsPerDistributionBucket =
         MaxNumberOfPendingInvitationsPerDistributionBucket;
         MaxNumberOfPendingInvitationsPerDistributionBucket;
     type MaxDataObjectSize = MaxDataObjectSize;
     type MaxDataObjectSize = MaxDataObjectSize;
+    type ContentId = u64;
 
 
     fn ensure_storage_working_group_leader_origin(origin: Self::Origin) -> DispatchResult {
     fn ensure_storage_working_group_leader_origin(origin: Self::Origin) -> DispatchResult {
         let account_id = ensure_signed(origin)?;
         let account_id = ensure_signed(origin)?;

+ 1 - 34
runtime/src/lib.rs

@@ -75,7 +75,6 @@ pub use pallet_staking::StakerStatus;
 pub use proposals_codex::ProposalsConfigParameters;
 pub use proposals_codex::ProposalsConfigParameters;
 pub use working_group;
 pub use working_group;
 
 
-use common::storage::{ContentParameters, StorageObjectOwner};
 pub use content;
 pub use content;
 pub use content::MaxNumber;
 pub use content::MaxNumber;
 
 
@@ -443,38 +442,6 @@ impl content::Trait for Runtime {
     type SeriesId = SeriesId;
     type SeriesId = SeriesId;
     type ChannelOwnershipTransferRequestId = ChannelOwnershipTransferRequestId;
     type ChannelOwnershipTransferRequestId = ChannelOwnershipTransferRequestId;
     type MaxNumberOfCuratorsPerGroup = MaxNumberOfCuratorsPerGroup;
     type MaxNumberOfCuratorsPerGroup = MaxNumberOfCuratorsPerGroup;
-    type StorageSystem = (); // TODO: Add storage integration
-}
-
-// TODO: Remove after the integration with the Content pallet.
-impl common::storage::StorageSystem<Runtime> for () {
-    fn atomically_add_content(
-        _: StorageObjectOwner<MemberId, ChannelId, DAOId>,
-        _: Vec<ContentParameters<ContentId, DataObjectTypeId>>,
-    ) -> sp_runtime::DispatchResult {
-        todo!()
-    }
-
-    fn can_add_content(
-        _: StorageObjectOwner<MemberId, ChannelId, DAOId>,
-        _: Vec<ContentParameters<ContentId, DataObjectTypeId>>,
-    ) -> sp_runtime::DispatchResult {
-        todo!()
-    }
-
-    fn atomically_remove_content(
-        _: &StorageObjectOwner<MemberId, ChannelId, DAOId>,
-        _: &[ContentId],
-    ) -> sp_runtime::DispatchResult {
-        todo!()
-    }
-
-    fn can_remove_content(
-        _: &StorageObjectOwner<MemberId, ChannelId, DAOId>,
-        _: &[ContentId],
-    ) -> sp_runtime::DispatchResult {
-        todo!()
-    }
 }
 }
 
 
 impl hiring::Trait for Runtime {
 impl hiring::Trait for Runtime {
@@ -531,7 +498,6 @@ impl common::MembershipTypes for Runtime {
 
 
 impl common::StorageOwnership for Runtime {
 impl common::StorageOwnership for Runtime {
     type ChannelId = ChannelId;
     type ChannelId = ChannelId;
-    type DAOId = DAOId;
     type ContentId = ContentId;
     type ContentId = ContentId;
     type DataObjectTypeId = DataObjectTypeId;
     type DataObjectTypeId = DataObjectTypeId;
 }
 }
@@ -723,6 +689,7 @@ impl storage::Trait for Runtime {
     type MaxNumberOfPendingInvitationsPerDistributionBucket =
     type MaxNumberOfPendingInvitationsPerDistributionBucket =
         MaxNumberOfPendingInvitationsPerDistributionBucket;
         MaxNumberOfPendingInvitationsPerDistributionBucket;
     type MaxDataObjectSize = MaxDataObjectSize;
     type MaxDataObjectSize = MaxDataObjectSize;
+    type ContentId = ContentId;
 
 
     fn ensure_storage_working_group_leader_origin(origin: Self::Origin) -> DispatchResult {
     fn ensure_storage_working_group_leader_origin(origin: Self::Origin) -> DispatchResult {
         StorageWorkingGroup::ensure_origin_is_active_leader(origin)
         StorageWorkingGroup::ensure_origin_is_active_leader(origin)

Some files were not shown because too many files changed in this diff