123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101 |
- import ContentDirectoryCommandBase from '../../base/ContentDirectoryCommandBase'
- import { flags } from '@oclif/command'
- import chalk from 'chalk'
- import { createTypeFromConstructor } from '@joystream/types'
- import { BagId } from '@joystream/types/storage'
- import ExitCodes from '../../ExitCodes'
- import { formatBalance } from '@polkadot/util'
- import BN from 'bn.js'
- export default class DeleteChannelCommand extends ContentDirectoryCommandBase {
- static description = 'Delete the channel and optionally all associated data objects.'
- static flags = {
- channelId: flags.integer({
- char: 'c',
- required: true,
- description: 'ID of the Channel',
- }),
- force: flags.boolean({
- char: 'f',
- default: false,
- description: 'Force-remove all associated channel data objects',
- }),
- }
- async getDataObjectsInfoFromQueryNode(channelId: number): Promise<[string, BN][]> {
- const dataObjects = await this.getQNApi().dataObjectsByBagId(`dynamic:channel:${channelId}`)
- if (dataObjects.length) {
- this.log('Following data objects are still associated with the channel:')
- dataObjects.forEach((o) => {
- let parentStr = ''
- if ('video' in o.type && o.type.video) {
- parentStr = ` (video: ${o.type.video.id})`
- }
- this.log(`- ${o.id} - ${o.type.__typename}${parentStr}`)
- })
- }
- return dataObjects.map((o) => [o.id, new BN(o.deletionPrize)])
- }
- async getDataObjectsInfoFromChain(channelId: number): Promise<[string, BN][]> {
- const dataObjects = await this.getApi().dataObjectsInBag(
- createTypeFromConstructor(BagId, { Dynamic: { Channel: channelId } })
- )
- if (dataObjects.length) {
- const dataObjectIds = dataObjects.map(([id]) => id.toString())
- this.log(`Following data objects are still associated with the channel: ${dataObjectIds.join(', ')}`)
- }
- return dataObjects.map(([id, o]) => [id.toString(), o.deletion_prize])
- }
- async run(): Promise<void> {
- const {
- flags: { channelId, force },
- } = this.parse(DeleteChannelCommand)
- // Context
- const channel = await this.getApi().channelById(channelId)
- const [actor, address] = await this.getChannelOwnerActor(channel)
- if (channel.num_videos.toNumber()) {
- this.error(
- `This channel still has ${channel.num_videos.toNumber()} associated video(s)!\n` +
- `Delete the videos first using ${chalk.magentaBright('content:deleteVideo')} command`
- )
- }
- const dataObjectsInfo = this.isQueryNodeUriSet()
- ? await this.getDataObjectsInfoFromQueryNode(channelId)
- : await this.getDataObjectsInfoFromChain(channelId)
- if (dataObjectsInfo.length) {
- if (!force) {
- this.error(`Cannot remove associated data objects unless ${chalk.magentaBright('--force')} flag is used`, {
- exit: ExitCodes.InvalidInput,
- })
- }
- const deletionPrize = dataObjectsInfo.reduce((sum, [, prize]) => sum.add(prize), new BN(0))
- this.log(
- `Data objects deletion prize of ${chalk.cyanBright(
- formatBalance(deletionPrize)
- )} will be transferred to ${chalk.magentaBright(address)}`
- )
- }
- await this.requireConfirmation(
- `Are you sure you want to remove channel ${chalk.magentaBright(channelId.toString())}${
- force ? ' and all associated data objects' : ''
- }?`
- )
- await this.sendAndFollowNamedTx(await this.getDecodedPair(address), 'content', 'deleteChannel', [
- actor,
- channelId,
- force ? dataObjectsInfo.length : 0,
- ])
- }
- }
|