createChannel.ts 3.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import { getInputJson } from '../../helpers/InputOutput'
  2. import { ChannelCreationInputParameters } from '../../Types'
  3. import { asValidatedMetadata, metadataToBytes } from '../../helpers/serialization'
  4. import { flags } from '@oclif/command'
  5. import { createType } from '@joystream/types'
  6. import { ChannelCreationParameters } from '@joystream/types/content'
  7. import { ChannelCreationInputSchema } from '../../schemas/ContentDirectory'
  8. import ContentDirectoryCommandBase from '../../base/ContentDirectoryCommandBase'
  9. import UploadCommandBase from '../../base/UploadCommandBase'
  10. import chalk from 'chalk'
  11. import { ChannelMetadata } from '@joystream/metadata-protobuf'
  12. import { ChannelId } from '@joystream/types/common'
  13. export default class CreateChannelCommand extends UploadCommandBase {
  14. static description = 'Create channel inside content directory.'
  15. static flags = {
  16. context: ContentDirectoryCommandBase.channelCreationContextFlag,
  17. input: flags.string({
  18. char: 'i',
  19. required: true,
  20. description: `Path to JSON file to use as input`,
  21. }),
  22. ...UploadCommandBase.flags,
  23. }
  24. async run(): Promise<void> {
  25. let { context, input } = this.parse(CreateChannelCommand).flags
  26. // Context
  27. if (!context) {
  28. context = await this.promptForChannelCreationContext()
  29. }
  30. const [actor, address] = await this.getContentActor(context)
  31. const { id: memberId } = await this.getRequiredMemberContext(true)
  32. const keypair = await this.getDecodedPair(address)
  33. const channelInput = await getInputJson<ChannelCreationInputParameters>(input, ChannelCreationInputSchema)
  34. const meta = asValidatedMetadata(ChannelMetadata, channelInput)
  35. const { collaborators, moderators, rewardAccount } = channelInput
  36. if (collaborators) {
  37. await this.validateMemberIdsSet(collaborators, 'collaborator')
  38. }
  39. if (moderators) {
  40. await this.validateMemberIdsSet(moderators, 'moderator')
  41. }
  42. const { coverPhotoPath, avatarPhotoPath } = channelInput
  43. const [resolvedAssets, assetIndices] = await this.resolveAndValidateAssets(
  44. { coverPhotoPath, avatarPhotoPath },
  45. input
  46. )
  47. meta.coverPhoto = assetIndices.coverPhotoPath
  48. meta.avatarPhoto = assetIndices.avatarPhotoPath
  49. // Preare and send the extrinsic
  50. const assets = await this.prepareAssetsForExtrinsic(resolvedAssets)
  51. const channelCreationParameters = createType<ChannelCreationParameters, 'ChannelCreationParameters'>(
  52. 'ChannelCreationParameters',
  53. {
  54. assets,
  55. meta: metadataToBytes(ChannelMetadata, meta),
  56. collaborators,
  57. moderators,
  58. reward_account: rewardAccount,
  59. }
  60. )
  61. this.jsonPrettyPrint(
  62. JSON.stringify({ assets: assets?.toJSON(), metadata: meta, collaborators, moderators, rewardAccount })
  63. )
  64. await this.requireConfirmation('Do you confirm the provided input?', true)
  65. const result = await this.sendAndFollowNamedTx(keypair, 'content', 'createChannel', [
  66. actor,
  67. channelCreationParameters,
  68. ])
  69. const channelCreatedEvent = this.getEvent(result, 'content', 'ChannelCreated')
  70. const channelId: ChannelId = channelCreatedEvent.data[1]
  71. this.log(chalk.green(`Channel with id ${chalk.cyanBright(channelId.toString())} successfully created!`))
  72. const dataObjectsUploadedEvent = this.findEvent(result, 'storage', 'DataObjectsUploaded')
  73. if (dataObjectsUploadedEvent) {
  74. const [objectIds] = dataObjectsUploadedEvent.data
  75. await this.uploadAssets(
  76. keypair,
  77. memberId.toNumber(),
  78. `dynamic:channel:${channelId.toString()}`,
  79. objectIds.map((id, index) => ({ dataObjectId: id, path: resolvedAssets[index].path })),
  80. input
  81. )
  82. }
  83. }
  84. }