瀏覽代碼

CLI: categories management support

iorveth 4 年之前
父節點
當前提交
431661d104

+ 38 - 1
cli/src/Types.ts

@@ -11,7 +11,12 @@ import { Opening, StakingPolicy, ApplicationStageKeys } from '@joystream/types/h
 import { Validator } from 'inquirer'
 import { NewAsset } from '@joystream/types/content'
 import { Bytes } from '@polkadot/types/primitive'
-import { VideoMetadata, ChannelMetadata } from '@joystream/content-metadata-protobuf'
+import {
+  VideoMetadata,
+  ChannelMetadata,
+  ChannelCategoryMetadata,
+  VideoCategoryMetadata,
+} from '@joystream/content-metadata-protobuf'
 
 // KeyringPair type extended with mandatory "meta.name"
 // It's used for accounts/keys management within CLI.
@@ -244,3 +249,35 @@ export type ChannelUpdateParameters = {
   new_meta: Bytes
   reward_account: Option<AccountId>
 }
+
+export type ChannelCategoryCreationParametersInput = {
+  meta: ChannelCategoryMetadata.AsObject
+}
+
+export type ChannelCategoryCreationParameters = {
+  meta: Bytes
+}
+
+export type ChannelCategoryUpdateParametersInput = {
+  meta: ChannelCategoryMetadata.AsObject
+}
+
+export type ChannelCategoryUpdateParameters = {
+  meta: Bytes
+}
+
+export type VideoCategoryCreationParametersInput = {
+  meta: VideoCategoryMetadata.AsObject
+}
+
+export type VideoCategoryCreationParameters = {
+  meta: Bytes
+}
+
+export type VideoCategoryUpdateParametersInput = {
+  meta: VideoCategoryMetadata.AsObject
+}
+
+export type VideoCategoryUpdateParameters = {
+  meta: Bytes
+}

+ 20 - 1
cli/src/base/ContentDirectoryCommandBase.ts

@@ -9,9 +9,11 @@ import { flags } from '@oclif/command'
 
 const CONTEXTS = ['Member', 'Curator', 'Lead'] as const
 const OWNER_CONTEXTS = ['Member', 'Curator'] as const
+const CATEGORIES_CONTEXTS = ['Lead', 'Curator'] as const
 
 type Context = typeof CONTEXTS[number]
 type OwnerContext = typeof OWNER_CONTEXTS[number]
+type CategoriesContext = typeof CATEGORIES_CONTEXTS[number]
 
 /**
  * Abstract base class for commands related to content directory
@@ -27,12 +29,19 @@ export default abstract class ContentDirectoryCommandBase extends RolesCommandBa
   })
 
   static ownerContextFlag = flags.enum({
-    name: 'context',
+    name: 'ownerContext',
     required: false,
     description: `Actor context to execute the command in (${OWNER_CONTEXTS.join('/')})`,
     options: [...OWNER_CONTEXTS],
   })
 
+  static categoriesContextFlag = flags.enum({
+    name: 'categoriesContext',
+    required: false,
+    description: `Actor context to execute the command in (${CATEGORIES_CONTEXTS.join('/')})`,
+    options: [...CATEGORIES_CONTEXTS],
+  })
+
   async promptForContext(message = 'Choose in which context you wish to execute the command'): Promise<Context> {
     return this.simplePrompt({
       message,
@@ -51,6 +60,16 @@ export default abstract class ContentDirectoryCommandBase extends RolesCommandBa
     })
   }
 
+  async promptForCategoriesContext(
+    message = 'Choose in which context you wish to execute the command'
+  ): Promise<CategoriesContext> {
+    return this.simplePrompt({
+      message,
+      type: 'list',
+      choices: CATEGORIES_CONTEXTS.map((c) => ({ name: c, value: c })),
+    })
+  }
+
   // Use when lead access is required in given command
   async requireLead(): Promise<void> {
     await this.getRequiredLead()

+ 54 - 0
cli/src/commands/content/createChannelCategory.ts

@@ -0,0 +1,54 @@
+import ContentDirectoryCommandBase from '../../base/ContentDirectoryCommandBase'
+import { IOFlags, getInputJson } from '../../helpers/InputOutput'
+import { ChannelCategoryCreationParameters, ChannelCategoryCreationParametersInput } from '../../Types'
+import { channelCategoryMetadataFromInput } from '../../helpers/serialization'
+
+export default class CreateChannelCategoryCommand extends ContentDirectoryCommandBase {
+  static description = 'Create channel category inside content directory.'
+  static flags = {
+    context: ContentDirectoryCommandBase.categoriesContextFlag,
+    input: IOFlags.input,
+  }
+
+  async run() {
+    let { context, input } = this.parse(CreateChannelCategoryCommand).flags
+
+    if (!context) {
+      context = await this.promptForCategoriesContext()
+    }
+
+    const currentAccount = await this.getRequiredSelectedAccount()
+    await this.requestAccountDecoding(currentAccount)
+
+    const actor = await this.getActor(context)
+
+    if (input) {
+      const channelCategoryCreationParametersInput = await getInputJson<ChannelCategoryCreationParametersInput>(input)
+
+      const api = await this.getOriginalApi()
+
+      const meta = channelCategoryMetadataFromInput(api, channelCategoryCreationParametersInput)
+
+      const channelCategoryCreationParameters: ChannelCategoryCreationParameters = {
+        meta,
+      }
+
+      this.jsonPrettyPrint(JSON.stringify(channelCategoryCreationParametersInput))
+
+      this.log('Meta: ' + meta)
+
+      const confirmed = await this.simplePrompt({ type: 'confirm', message: 'Do you confirm the provided input?' })
+
+      if (confirmed) {
+        this.log('Sending the extrinsic...')
+
+        await this.sendAndFollowNamedTx(currentAccount, 'content', 'createChannelCategory', [
+          actor,
+          channelCategoryCreationParameters,
+        ])
+      }
+    } else {
+      this.error('Input invalid or was not provided...')
+    }
+  }
+}

+ 54 - 0
cli/src/commands/content/createVideoCategory.ts

@@ -0,0 +1,54 @@
+import ContentDirectoryCommandBase from '../../base/ContentDirectoryCommandBase'
+import { IOFlags, getInputJson } from '../../helpers/InputOutput'
+import { VideoCategoryCreationParameters, VideoCategoryCreationParametersInput } from '../../Types'
+import { videoCategoryMetadataFromInput } from '../../helpers/serialization'
+
+export default class CreateVideoCategoryCommand extends ContentDirectoryCommandBase {
+  static description = 'Create video category inside content directory.'
+  static flags = {
+    context: ContentDirectoryCommandBase.categoriesContextFlag,
+    input: IOFlags.input,
+  }
+
+  async run() {
+    let { context, input } = this.parse(CreateVideoCategoryCommand).flags
+
+    if (!context) {
+      context = await this.promptForCategoriesContext()
+    }
+
+    const currentAccount = await this.getRequiredSelectedAccount()
+    await this.requestAccountDecoding(currentAccount)
+
+    const actor = await this.getActor(context)
+
+    if (input) {
+      const videoCategoryCreationParametersInput = await getInputJson<VideoCategoryCreationParametersInput>(input)
+
+      const api = await this.getOriginalApi()
+
+      const meta = videoCategoryMetadataFromInput(api, videoCategoryCreationParametersInput)
+
+      const videoCategoryCreationParameters: VideoCategoryCreationParameters = {
+        meta,
+      }
+
+      this.jsonPrettyPrint(JSON.stringify(videoCategoryCreationParametersInput))
+
+      this.log('Meta: ' + meta)
+
+      const confirmed = await this.simplePrompt({ type: 'confirm', message: 'Do you confirm the provided input?' })
+
+      if (confirmed) {
+        this.log('Sending the extrinsic...')
+
+        await this.sendAndFollowNamedTx(currentAccount, 'content', 'createVideoCategory', [
+          actor,
+          videoCategoryCreationParameters,
+        ])
+      }
+    } else {
+      this.error('Input invalid or was not provided...')
+    }
+  }
+}

+ 54 - 0
cli/src/commands/content/updateChannelCategory.ts

@@ -0,0 +1,54 @@
+import ContentDirectoryCommandBase from '../../base/ContentDirectoryCommandBase'
+import { IOFlags, getInputJson } from '../../helpers/InputOutput'
+import { ChannelCategoryUpdateParameters, ChannelCategoryUpdateParametersInput } from '../../Types'
+import { channelCategoryMetadataFromInput } from '../../helpers/serialization'
+
+export default class CreateChannelCategoryCommand extends ContentDirectoryCommandBase {
+  static description = 'Update channel category inside content directory.'
+  static flags = {
+    context: ContentDirectoryCommandBase.categoriesContextFlag,
+    input: IOFlags.input,
+  }
+
+  async run() {
+    let { context, input } = this.parse(CreateChannelCategoryCommand).flags
+
+    if (!context) {
+      context = await this.promptForCategoriesContext()
+    }
+
+    const currentAccount = await this.getRequiredSelectedAccount()
+    await this.requestAccountDecoding(currentAccount)
+
+    const actor = await this.getActor(context)
+
+    if (input) {
+      const channelCategoryUpdateParametersInput = await getInputJson<ChannelCategoryUpdateParametersInput>(input)
+
+      const api = await this.getOriginalApi()
+
+      const meta = channelCategoryMetadataFromInput(api, channelCategoryUpdateParametersInput)
+
+      const channelCategoryUpdateParameters: ChannelCategoryUpdateParameters = {
+        meta,
+      }
+
+      this.jsonPrettyPrint(JSON.stringify(channelCategoryUpdateParametersInput))
+
+      this.log('Meta: ' + meta)
+
+      const confirmed = await this.simplePrompt({ type: 'confirm', message: 'Do you confirm the provided input?' })
+
+      if (confirmed) {
+        this.log('Sending the extrinsic...')
+
+        await this.sendAndFollowNamedTx(currentAccount, 'content', 'updateChannelCategory', [
+          actor,
+          channelCategoryUpdateParameters,
+        ])
+      }
+    } else {
+      this.error('Input invalid or was not provided...')
+    }
+  }
+}

+ 54 - 0
cli/src/commands/content/updateVideoCategory.ts

@@ -0,0 +1,54 @@
+import ContentDirectoryCommandBase from '../../base/ContentDirectoryCommandBase'
+import { IOFlags, getInputJson } from '../../helpers/InputOutput'
+import { VideoCategoryUpdateParameters, VideoCategoryUpdateParametersInput } from '../../Types'
+import { videoCategoryMetadataFromInput } from '../../helpers/serialization'
+
+export default class UpdateVideoCategoryCommand extends ContentDirectoryCommandBase {
+  static description = 'Update video category inside content directory.'
+  static flags = {
+    context: ContentDirectoryCommandBase.categoriesContextFlag,
+    input: IOFlags.input,
+  }
+
+  async run() {
+    let { context, input } = this.parse(UpdateVideoCategoryCommand).flags
+
+    if (!context) {
+      context = await this.promptForCategoriesContext()
+    }
+
+    const currentAccount = await this.getRequiredSelectedAccount()
+    await this.requestAccountDecoding(currentAccount)
+
+    const actor = await this.getActor(context)
+
+    if (input) {
+      const videoCategoryUpdateParametersInput = await getInputJson<VideoCategoryUpdateParametersInput>(input)
+
+      const api = await this.getOriginalApi()
+
+      const meta = videoCategoryMetadataFromInput(api, videoCategoryUpdateParametersInput)
+
+      const videoCategoryUpdateParameters: VideoCategoryUpdateParameters = {
+        meta,
+      }
+
+      this.jsonPrettyPrint(JSON.stringify(videoCategoryUpdateParameters))
+
+      this.log('Meta: ' + meta)
+
+      const confirmed = await this.simplePrompt({ type: 'confirm', message: 'Do you confirm the provided input?' })
+
+      if (confirmed) {
+        this.log('Sending the extrinsic...')
+
+        await this.sendAndFollowNamedTx(currentAccount, 'content', 'updateVideoCategory', [
+          actor,
+          videoCategoryUpdateParameters,
+        ])
+      }
+    } else {
+      this.error('Input invalid or was not provided...')
+    }
+  }
+}

+ 28 - 0
cli/src/helpers/serialization.ts

@@ -4,12 +4,18 @@ import {
   License,
   MediaType,
   ChannelMetadata,
+  ChannelCategoryMetadata,
+  VideoCategoryMetadata,
 } from '@joystream/content-metadata-protobuf'
 import {
   VideoUpdateParametersInput,
   VideoCreationParametersInput,
   ChannelUpdateParametersInput,
   ChannelCreationParametersInput,
+  ChannelCategoryCreationParametersInput,
+  ChannelCategoryUpdateParametersInput,
+  VideoCategoryCreationParametersInput,
+  VideoCategoryUpdateParametersInput,
 } from '../Types'
 import { ApiPromise } from '@polkadot/api'
 import { Bytes } from '@polkadot/types/primitive'
@@ -75,3 +81,25 @@ export function channelMetadataFromInput(
   const serialized = channelMetadata.serializeBinary()
   return binaryToMeta(api, serialized)
 }
+
+export function channelCategoryMetadataFromInput(
+  api: ApiPromise,
+  channelCategoryParametersInput: ChannelCategoryCreationParametersInput | ChannelCategoryUpdateParametersInput
+): Bytes {
+  const channelCategoryMetadata = new ChannelCategoryMetadata()
+  channelCategoryMetadata.setName(channelCategoryParametersInput.meta.name!)
+
+  const serialized = channelCategoryMetadata.serializeBinary()
+  return binaryToMeta(api, serialized)
+}
+
+export function videoCategoryMetadataFromInput(
+  api: ApiPromise,
+  videoCategoryParametersInput: VideoCategoryCreationParametersInput | VideoCategoryUpdateParametersInput
+): Bytes {
+  const videoCategoryMetadata = new VideoCategoryMetadata()
+  videoCategoryMetadata.setName(videoCategoryParametersInput.meta.name!)
+
+  const serialized = videoCategoryMetadata.serializeBinary()
+  return binaryToMeta(api, serialized)
+}