Jelajahi Sumber

Remove storage auth, remove category migrations, add a way to force custom channel owner

Leszek Wiesner 3 tahun lalu
induk
melakukan
50bd731437

+ 44 - 51
utils/migration-scripts/README.md

@@ -28,96 +28,89 @@ USAGE
 <!-- usagestop -->
 # Commands
 <!-- commands -->
-* [`migration-scripts giza:migrateContent`](#migration-scripts-gizamigratecontent)
-* [`migration-scripts giza:retryFailedUploads`](#migration-scripts-gizaretryfaileduploads)
 * [`migration-scripts help [COMMAND]`](#migration-scripts-help-command)
+* [`migration-scripts sumer-giza:migrateContent`](#migration-scripts-sumer-gizamigratecontent)
+* [`migration-scripts sumer-giza:retryFailedUploads`](#migration-scripts-sumer-gizaretryfaileduploads)
 
-## `migration-scripts giza:migrateContent`
+## `migration-scripts help [COMMAND]`
+
+display help for migration-scripts
 
 ```
 USAGE
-  $ migration-scripts giza:migrateContent
+  $ migration-scripts help [COMMAND]
+
+ARGUMENTS
+  COMMAND  command to show help for
+
+OPTIONS
+  --all  see all commands in CLI
+```
+
+_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v3.2.3/src/commands/help.ts)_
+
+## `migration-scripts sumer-giza:migrateContent`
+
+```
+USAGE
+  $ migration-scripts sumer-giza:migrateContent
 
 OPTIONS
   -c, --channelIds=channelIds                                  (required) Channel ids to migrate
-  --channelBatchSize=channelBatchSize                          [default: 100] Channel batch size
+  --channelBatchSize=channelBatchSize                          [default: 20] Channel batch size
 
-  --dataDir=dataDir                                            [default: /tmp/joystream/giza-migration] Directory for
-                                                               storing data objects to upload
+  --dataDir=dataDir                                            [default: /tmp/joystream/sumer-giza-migration] Directory
+                                                               for storing data objects to upload
 
-  --dev                                                        Turns on dev mode
+  --forceChannelOwnerMemberId=forceChannelOwnerMemberId        Can be used to force a specific channel owner for all
+                                                               channels, allowing to test the script in dev environment
 
   --migrationStatePath=migrationStatePath                      [default:
-                                                               /home/leszek/projects/joystream/joystream-ws-1/utils/migr
-                                                               ation-scripts/results/giza] Path to migration
-                                                               state/results directory
+                                                               /home/leszek/projects/joystream/joystream-ws-2/utils/migr
+                                                               ation-scripts/results/sumer-giza] Path to migration
+                                                               results directory
 
-  --preferredDownloadSpEndpoints=preferredDownloadSpEndpoints  [default: https://rome-rpc-4.joystream.org] Preferred
-                                                               storage node endpoints when downloading data objects
-                                                               (comma-separated)
+  --preferredDownloadSpEndpoints=preferredDownloadSpEndpoints  [default: https://storage-1.joystream.org/storage]
+                                                               Preferred storage node endpoints when downloading data
+                                                               objects
 
   --queryNodeUri=queryNodeUri                                  [default: https://hydra.joystream.org/graphql] Query node
                                                                uri
 
   --sudoUri=sudoUri                                            [default: //Alice] Sudo key Substrate uri
 
-  --uploadMemberControllerUri=uploadMemberControllerUri        [default: //Alice] Giza upload member controller uri
-
-  --uploadMemberId=uploadMemberId                              [default: 0] Giza member id to use for uploading
-
   --uploadSpBucketId=uploadSpBucketId                          [default: 0] Giza storage bucket id
 
   --uploadSpEndpoint=uploadSpEndpoint                          [default: http://localhost:3333] Giza storage node
                                                                endpoint to use for uploading
 
-  --videoBatchSize=videoBatchSize                              [default: 100] Video batch size
+  --videoBatchSize=videoBatchSize                              [default: 20] Video batch size
 
   --wsProviderEndpointUri=wsProviderEndpointUri                [default: ws://localhost:9944] WS provider endpoint uri
                                                                (Giza)
 ```
 
-_See code: [src/commands/giza/migrateContent.ts](https://github.com/Joystream/joystream/blob/v0.1.0/src/commands/giza/migrateContent.ts)_
+_See code: [src/commands/sumer-giza/migrateContent.ts](https://github.com/Joystream/joystream/blob/v0.1.0/src/commands/sumer-giza/migrateContent.ts)_
 
-## `migration-scripts giza:retryFailedUploads`
+## `migration-scripts sumer-giza:retryFailedUploads`
 
 ```
 USAGE
-  $ migration-scripts giza:retryFailedUploads
+  $ migration-scripts sumer-giza:retryFailedUploads
 
 OPTIONS
-  -f, --failedUploadsPath=failedUploadsPath              (required) Path to failed uploads file
+  -f, --failedUploadsPath=failedUploadsPath      (required) Path to failed uploads file
 
-  --dataDir=dataDir                                      [default: /tmp/joystream/giza-migration] Directory for storing
-                                                         data objects to upload
+  --dataDir=dataDir                              [default: /tmp/joystream/sumer-giza-migration] Directory where data
+                                                 objects to upload are stored
 
-  --uploadMemberControllerUri=uploadMemberControllerUri  [default: //Alice] Giza upload member controller uri
+  --uploadSpBucketId=uploadSpBucketId            [default: 0] Giza storage bucket id
 
-  --uploadMemberId=uploadMemberId                        [default: 0] Giza member id to use for uploading
+  --uploadSpEndpoint=uploadSpEndpoint            [default: http://localhost:3333] Giza storage node endpoint to use for
+                                                 uploading
 
-  --uploadSpBucketId=uploadSpBucketId                    [default: 0] Giza storage bucket id
-
-  --uploadSpEndpoint=uploadSpEndpoint                    [default: http://localhost:3333] Giza storage node endpoint to
-                                                         use for uploading
-
-  --wsProviderEndpointUri=wsProviderEndpointUri          [default: ws://localhost:9944] WS provider endpoint uri (Giza)
+  --wsProviderEndpointUri=wsProviderEndpointUri  [default: ws://localhost:9944] WS provider endpoint uri (Giza)
 ```
 
-_See code: [src/commands/giza/retryFailedUploads.ts](https://github.com/Joystream/joystream/blob/v0.1.0/src/commands/giza/retryFailedUploads.ts)_
-
-## `migration-scripts help [COMMAND]`
-
-display help for migration-scripts
-
-```
-USAGE
-  $ migration-scripts help [COMMAND]
-
-ARGUMENTS
-  COMMAND  command to show help for
-
-OPTIONS
-  --all  see all commands in CLI
-```
-
-_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v3.2.3/src/commands/help.ts)_
+_See code: [src/commands/sumer-giza/retryFailedUploads.ts](https://github.com/Joystream/joystream/blob/v0.1.0/src/commands/sumer-giza/retryFailedUploads.ts)_
 <!-- commandsstop -->

+ 6 - 13
utils/migration-scripts/src/commands/sumer-giza/migrateContent.ts

@@ -35,14 +35,15 @@ export class MigrateContentCommand extends Command {
       description: 'Video batch size',
       default: 20,
     }),
-    dev: flags.boolean({
-      description: 'Turns on dev mode (assumes that member 0 (Alice) exists)',
-      default: false,
+    forceChannelOwnerMemberId: flags.integer({
+      description:
+        'Can be used to force a specific channel owner for all channels, allowing to easily test the script in dev environment',
+      required: false,
     }),
     preferredDownloadSpEndpoints: flags.string({
       multiple: true,
-      description: 'Preferred storage node endpoints when downloading data objects (comma-separated)',
-      default: ['https://rome-rpc-4.joystream.org'],
+      description: 'Preferred storage node endpoints when downloading data objects',
+      default: ['https://storage-1.joystream.org/storage'],
     }),
     uploadSpEndpoint: flags.string({
       description: 'Giza storage node endpoint to use for uploading',
@@ -52,14 +53,6 @@ export class MigrateContentCommand extends Command {
       description: 'Giza storage bucket id',
       default: 0,
     }),
-    uploadMemberId: flags.integer({
-      description: 'Giza member id to use for uploading',
-      default: 0,
-    }),
-    uploadMemberControllerUri: flags.string({
-      description: 'Giza upload member controller uri',
-      default: '//Alice',
-    }),
     migrationStatePath: flags.string({
       description: 'Path to migration results directory',
       default: path.join(__dirname, '../../../results/sumer-giza'),

+ 0 - 8
utils/migration-scripts/src/commands/sumer-giza/retryFailedUploads.ts

@@ -23,14 +23,6 @@ export class RetryFailedUploadsCommand extends Command {
       description: 'Giza storage bucket id',
       default: 0,
     }),
-    uploadMemberId: flags.integer({
-      description: 'Giza member id to use for uploading',
-      default: 0,
-    }),
-    uploadMemberControllerUri: flags.string({
-      description: 'Giza upload member controller uri',
-      default: '//Alice',
-    }),
     failedUploadsPath: flags.string({
       char: 'f',
       description: 'Path to failed uploads file',

+ 3 - 49
utils/migration-scripts/src/sumer-giza/AssetsManager.ts

@@ -8,10 +8,7 @@ import { BagId, DataObjectCreationParameters, DataObjectId, UploadParameters } f
 import { IEvent } from '@polkadot/types/types'
 import { Vec } from '@polkadot/types'
 import { Balance } from '@polkadot/types/interfaces'
-import { u8aToHex } from '@polkadot/util'
 import FormData from 'form-data'
-import { Keyring } from '@polkadot/keyring'
-import { KeyringPair } from '@polkadot/keyring/types'
 import { ImageResizer } from './ImageResizer'
 import { QueryNodeApi } from './sumer-query-node/api'
 import { RuntimeApi } from '../RuntimeApi'
@@ -25,8 +22,6 @@ export type AssetsManagerConfig = {
   preferredDownloadSpEndpoints?: string[]
   uploadSpBucketId: number
   uploadSpEndpoint: string
-  uploadMemberControllerUri: string
-  uploadMemberId: number
   dataDir: string
 }
 
@@ -38,7 +33,6 @@ export type AssetsManagerParams = {
 
 export type AssetsManagerLoadableParams = {
   dataObjectFeePerMB: BN
-  uploadMemberKey: KeyringPair
   sumerStorageProviderEndpoints: string[]
 }
 
@@ -58,7 +52,6 @@ export class AssetsManager {
   private api: RuntimeApi
   private config: AssetsManagerConfig
   public readonly dataObjectFeePerMB: BN
-  private uploadMemberKey: KeyringPair
   private sumerStorageProviderEndpoints: string[]
   private resizer: ImageResizer
   private queuedUploads: Set<string>
@@ -71,18 +64,16 @@ export class AssetsManager {
   public static async create(params: AssetsManagerParams): Promise<AssetsManager> {
     const { api } = params
     const dataObjectFeePerMB = await api.query.storage.dataObjectPerMegabyteFee()
-    const uploadMemberKey = await AssetsManager.getUploadMemberKey(params)
     const sumerStorageProviderEndpoints = params.queryNodeApi
       ? await AssetsManager.getSumerStorageProviderEndpoints(params.queryNodeApi)
       : []
-    return new AssetsManager(params, { dataObjectFeePerMB, uploadMemberKey, sumerStorageProviderEndpoints })
+    return new AssetsManager(params, { dataObjectFeePerMB, sumerStorageProviderEndpoints })
   }
 
   private constructor(params: AssetsManagerParams, loadableParams: AssetsManagerLoadableParams) {
     const { api, config } = params
-    const { dataObjectFeePerMB, uploadMemberKey, sumerStorageProviderEndpoints } = loadableParams
+    const { dataObjectFeePerMB, sumerStorageProviderEndpoints } = loadableParams
     this.dataObjectFeePerMB = dataObjectFeePerMB
-    this.uploadMemberKey = uploadMemberKey
     this.sumerStorageProviderEndpoints = sumerStorageProviderEndpoints
     this.api = api
     this.config = config
@@ -92,20 +83,6 @@ export class AssetsManager {
     fs.mkdirSync(this.assetPath(''), { recursive: true })
   }
 
-  private static async getUploadMemberKey({ api, config }: AssetsManagerParams): Promise<KeyringPair> {
-    const { uploadMemberControllerUri, uploadMemberId } = config
-    const keyring = new Keyring({ type: 'sr25519' })
-    const uploadMemberController = keyring.createFromUri(uploadMemberControllerUri)
-    const uploadMember = await api.query.members.membershipById(uploadMemberId)
-    if (uploadMember.controller_account.toString() !== uploadMemberController.address) {
-      throw new Error(
-        `Invalid upload member controller key! ` +
-          `Expected: ${uploadMember.controller_account.toString()}, Got: ${uploadMemberController.address}`
-      )
-    }
-    return uploadMemberController
-  }
-
   private static async getSumerStorageProviderEndpoints(queryNodeApi: QueryNodeApi): Promise<string[]> {
     const endpoints: string[] = []
     const workers = await queryNodeApi.getStorageWorkers()
@@ -246,8 +223,7 @@ export class AssetsManager {
 
   private async uploadDataObject(bagId: string, dataObjectId: number): Promise<void> {
     const {
-      uploadMemberKey,
-      config: { uploadMemberId, uploadSpBucketId, uploadSpEndpoint },
+      config: { uploadSpBucketId, uploadSpEndpoint },
     } = this
     const dataObject = await this.api.query.storage.dataObjectsById(
       { Dynamic: { Channel: bagId.split(':')[2] } },
@@ -257,27 +233,6 @@ export class AssetsManager {
     if (!fs.existsSync(dataPath)) {
       throw new Error(`Cannot upload object: ${dataObjectId}: ${dataPath} not found`)
     }
-    const tokenRequestPayload = {
-      accountId: uploadMemberKey.address,
-      bagId,
-      dataObjectId,
-      memberId: uploadMemberId,
-      storageBucketId: uploadSpBucketId,
-    }
-    const signature = u8aToHex(uploadMemberKey.sign(JSON.stringify(tokenRequestPayload)))
-
-    let token: string
-    try {
-      const response = await axios.post(urljoin(uploadSpEndpoint, 'api/v1/authToken'), {
-        data: tokenRequestPayload,
-        signature,
-      })
-      token = response.data.token
-    } catch (e) {
-      const msg = this.reqErrorMessage(e)
-      console.error(`Upload token request (objectId: ${dataObjectId}) to ${uploadSpEndpoint} failed: ${msg}`)
-      return
-    }
 
     const fileStream = fs.createReadStream(dataPath)
     const formData = new FormData()
@@ -293,7 +248,6 @@ export class AssetsManager {
         data: formData,
         maxBodyLength: Infinity,
         headers: {
-          'x-api-key': token,
           'content-type': 'multipart/form-data',
           ...formData.getHeaders(),
         },

+ 0 - 1
utils/migration-scripts/src/sumer-giza/BaseMigration.ts

@@ -21,7 +21,6 @@ export type MigrationStateJson = {
 export type BaseMigrationConfig = {
   migrationStatePath: string
   sudoUri: string
-  dev: boolean
 }
 
 export type BaseMigrationParams = {

+ 0 - 22
utils/migration-scripts/src/sumer-giza/CategoryMigration.ts

@@ -1,22 +0,0 @@
-import { BaseMigration, MigrationResult } from './BaseMigration'
-
-export abstract class CategoryMigration extends BaseMigration {
-  protected contentLeadKey!: string
-
-  public async init(): Promise<void> {
-    await super.init()
-    await this.loadContentLeadKey()
-  }
-
-  public abstract run(): Promise<MigrationResult>
-
-  private async loadContentLeadKey(): Promise<void> {
-    const { api } = this
-    const leadId = await api.query.contentWorkingGroup.currentLead()
-    if (!leadId.isSome) {
-      throw new Error('ContentWorkingGroup lead must be set!')
-    }
-    const leadWorker = await api.query.contentWorkingGroup.workerById(leadId.unwrap())
-    this.contentLeadKey = leadWorker.role_account_id.toString()
-  }
-}

+ 0 - 58
utils/migration-scripts/src/sumer-giza/ChannelCategoriesMigration.ts

@@ -1,58 +0,0 @@
-import { ChannelCategoryMetadata } from '@joystream/metadata-protobuf'
-import { ChannelCategoryId } from '@joystream/types/content'
-import { MigrationResult } from './BaseMigration'
-import { CategoryMigration } from './CategoryMigration'
-
-export class ChannelCategoriesMigration extends CategoryMigration {
-  name = 'Channel categories migration'
-
-  public async run(): Promise<MigrationResult> {
-    await this.init()
-    const { api } = this
-    const allCategories = await this.queryNodeApi.getChannelCategories()
-    const categoriesToMigrate = allCategories.filter((c) => !this.idsMap.has(parseInt(c.id)))
-
-    if (!categoriesToMigrate.length) {
-      console.log('All channel categories already migrated, skipping...')
-      return this.getResult()
-    }
-
-    console.log(`Migrating ${categoriesToMigrate.length} channel categories...`)
-    const txs = categoriesToMigrate
-      .sort((a, b) => parseInt(a.id) - parseInt(b.id))
-      .map((c) => {
-        const meta = new ChannelCategoryMetadata({ name: c.name })
-        const metaBytes = '0x' + Buffer.from(ChannelCategoryMetadata.encode(meta).finish()).toString('hex')
-        return api.tx.sudo.sudoAs(
-          this.contentLeadKey,
-          api.tx.content.createChannelCategory('Lead', {
-            meta: metaBytes,
-          })
-        )
-      })
-
-    const result = await api.sendExtrinsic(this.sudo, api.tx.utility.batch(txs))
-    const categoryCreatedEvents = api.findEvents(result, 'content', 'ChannelCategoryCreated')
-    const createdCategoryIds: ChannelCategoryId[] = categoryCreatedEvents.map((e) => e.data[0])
-
-    if (createdCategoryIds.length !== categoriesToMigrate.length) {
-      this.extractFailedSudoAsMigrations(result, categoriesToMigrate)
-    }
-
-    let newCategoryIndex = 0
-    categoriesToMigrate.forEach((c) => {
-      if (this.failedMigrations.has(parseInt(c.id))) {
-        return
-      }
-      const newCategoryId = createdCategoryIds[newCategoryIndex++]
-      this.idsMap.set(parseInt(c.id), newCategoryId.toNumber())
-    })
-    console.log(`Channel categories map created!`, this.idsMap.entries())
-    if (this.failedMigrations.size) {
-      throw new Error(`Failed to create some channel categories: ${Array.from(this.failedMigrations).join(', ')}`)
-    }
-    console.log(`All channel categories succesfully migrated!`)
-
-    return this.getResult()
-  }
-}

+ 7 - 14
utils/migration-scripts/src/sumer-giza/ChannelsMigration.ts

@@ -12,11 +12,12 @@ import { MigrationResult } from './BaseMigration'
 export type ChannelsMigrationConfig = AssetsMigrationConfig & {
   channelIds: number[]
   channelBatchSize: number
+  forceChannelOwnerMemberId: number | undefined
 }
 
 export type ChannelsMigrationParams = AssetsMigrationParams & {
   config: ChannelsMigrationConfig
-  categoriesMap: Map<number, number>
+  forcedChannelOwner: { id: string; controllerAccount: string } | undefined
 }
 
 export type ChannelsMigrationResult = MigrationResult & {
@@ -26,21 +27,13 @@ export type ChannelsMigrationResult = MigrationResult & {
 export class ChannelMigration extends AssetsMigration {
   name = 'Channels migration'
   protected config: ChannelsMigrationConfig
-  protected categoriesMap: Map<number, number>
   protected videoIds: number[] = []
+  protected forcedChannelOwner: { id: string; controllerAccount: string } | undefined
 
   public constructor(params: ChannelsMigrationParams) {
     super(params)
     this.config = params.config
-    this.categoriesMap = params.categoriesMap
-  }
-
-  private getNewCategoryId(oldCategoryId: string | null | undefined): Long | undefined {
-    if (typeof oldCategoryId !== 'string') {
-      return undefined
-    }
-    const newCategoryId = this.categoriesMap.get(parseInt(oldCategoryId))
-    return newCategoryId ? Long.fromNumber(newCategoryId) : undefined
+    this.forcedChannelOwner = params.forcedChannelOwner
   }
 
   private getChannelOwnerMember({ id, ownerMember }: ChannelFieldsFragment) {
@@ -48,8 +41,8 @@ export class ChannelMigration extends AssetsMigration {
       throw new Error(`Chanel ownerMember missing: ${id}. Only member-owned channels are supported!`)
     }
 
-    if (this.config.dev) {
-      return { id: '0', controllerAccount: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY' }
+    if (this.forcedChannelOwner) {
+      return this.forcedChannelOwner
     }
 
     return ownerMember
@@ -136,7 +129,7 @@ export class ChannelMigration extends AssetsMigration {
     const meta = new ChannelMetadata({
       title,
       description,
-      category: this.getNewCategoryId(categoryId),
+      category: categoryId ? Long.fromString(categoryId) : undefined,
       avatarPhoto: preparedAssets.avatar?.index,
       coverPhoto: preparedAssets.coverPhoto?.index,
       isPublic,

+ 19 - 9
utils/migration-scripts/src/sumer-giza/ContentMigration.ts

@@ -2,8 +2,6 @@ import { WsProvider } from '@polkadot/api'
 import { QueryNodeApi } from './sumer-query-node/api'
 import { RuntimeApi } from '../RuntimeApi'
 import { VideosMigration } from './VideosMigration'
-import { ChannelCategoriesMigration } from './ChannelCategoriesMigration'
-import { VideoCategoriesMigration } from './VideoCategoriesMigration'
 import { ChannelMigration } from './ChannelsMigration'
 
 export type ContentMigrationConfig = {
@@ -14,12 +12,10 @@ export type ContentMigrationConfig = {
   dataDir: string
   channelBatchSize: number
   videoBatchSize: number
-  dev: boolean
+  forceChannelOwnerMemberId: number | undefined
   preferredDownloadSpEndpoints?: string[]
   uploadSpBucketId: number
   uploadSpEndpoint: string
-  uploadMemberControllerUri: string
-  uploadMemberId: number
   migrationStatePath: string
 }
 
@@ -36,24 +32,38 @@ export class ContentMigration {
     this.config = config
   }
 
+  private async getForcedChannelOwner(): Promise<{ id: string; controllerAccount: string } | undefined> {
+    const { forceChannelOwnerMemberId } = this.config
+    if (forceChannelOwnerMemberId) {
+      const ownerMember = await this.api.query.members.membershipById(forceChannelOwnerMemberId)
+      if (ownerMember.isEmpty) {
+        throw new Error(`Membership by id ${forceChannelOwnerMemberId} not found!`)
+      }
+      return {
+        id: forceChannelOwnerMemberId.toString(),
+        controllerAccount: ownerMember.controller_account.toString(),
+      }
+    }
+    return undefined
+  }
+
   public async run(): Promise<void> {
     const { api, queryNodeApi, config } = this
     await this.api.isReadyOrError
-    const { idsMap: channelCategoriesMap } = await new ChannelCategoriesMigration({ api, queryNodeApi, config }).run()
-    const { idsMap: videoCategoriesMap } = await new VideoCategoriesMigration({ api, queryNodeApi, config }).run()
+    const forcedChannelOwner = await this.getForcedChannelOwner()
     const { idsMap: channelsMap, videoIds } = await new ChannelMigration({
       api,
       queryNodeApi,
       config,
-      categoriesMap: channelCategoriesMap,
+      forcedChannelOwner,
     }).run()
     await new VideosMigration({
       api,
       queryNodeApi,
       config,
-      categoriesMap: videoCategoriesMap,
       channelsMap,
       videoIds,
+      forcedChannelOwner,
     }).run()
   }
 }

+ 0 - 56
utils/migration-scripts/src/sumer-giza/VideoCategoriesMigration.ts

@@ -1,56 +0,0 @@
-import { VideoCategoryMetadata } from '@joystream/metadata-protobuf'
-import { VideoCategoryId } from '@joystream/types/content'
-import { MigrationResult } from './BaseMigration'
-import { CategoryMigration } from './CategoryMigration'
-
-export class VideoCategoriesMigration extends CategoryMigration {
-  name = 'Video categories migration'
-  public async run(): Promise<MigrationResult> {
-    await this.init()
-    const { api } = this
-    const allCategories = await this.queryNodeApi.getVideoCategories()
-    const categoriesToMigrate = allCategories.filter((c) => !this.idsMap.has(parseInt(c.id)))
-
-    if (!categoriesToMigrate.length) {
-      console.log('All video categories already migrated, skipping...')
-      return this.getResult()
-    }
-
-    console.log(`Migrating ${categoriesToMigrate.length} video categories...`)
-    const txs = categoriesToMigrate
-      .sort((a, b) => parseInt(a.id) - parseInt(b.id))
-      .map((c) => {
-        const meta = new VideoCategoryMetadata({ name: c.name })
-        const metaBytes = '0x' + Buffer.from(VideoCategoryMetadata.encode(meta).finish()).toString('hex')
-        return api.tx.sudo.sudoAs(
-          this.contentLeadKey,
-          api.tx.content.createVideoCategory('Lead', {
-            meta: metaBytes,
-          })
-        )
-      })
-
-    const result = await api.sendExtrinsic(this.sudo, api.tx.utility.batch(txs))
-    const categoryCreatedEvents = api.findEvents(result, 'content', 'VideoCategoryCreated')
-    const createdCategoryIds: VideoCategoryId[] = categoryCreatedEvents.map((e) => e.data[1])
-
-    if (createdCategoryIds.length !== categoriesToMigrate.length) {
-      this.extractFailedSudoAsMigrations(result, categoriesToMigrate)
-    }
-
-    let newCategoryIndex = 0
-    categoriesToMigrate.forEach((c) => {
-      if (this.failedMigrations.has(parseInt(c.id))) {
-        return
-      }
-      const newCategoryId = createdCategoryIds[newCategoryIndex++]
-      this.idsMap.set(parseInt(c.id), newCategoryId.toNumber())
-    })
-    console.log(`Video categories map created!`, this.idsMap.entries())
-    if (this.failedMigrations.size) {
-      throw new Error(`Failed to create some video categories: ${Array.from(this.failedMigrations).join(', ')}`)
-    }
-    console.log(`All video categories succesfully migrated!`)
-    return this.getResult()
-  }
-}

+ 7 - 15
utils/migration-scripts/src/sumer-giza/VideosMigration.ts

@@ -16,31 +16,23 @@ export type VideosMigrationConfig = AssetsMigrationConfig & {
 export type VideosMigrationParams = AssetsMigrationParams & {
   config: VideosMigrationConfig
   videoIds: number[]
-  categoriesMap: Map<number, number>
   channelsMap: Map<number, number>
+  forcedChannelOwner: { id: string; controllerAccount: string } | undefined
 }
 
 export class VideosMigration extends AssetsMigration {
   name = 'Videos migration'
   protected config: VideosMigrationConfig
-  protected categoriesMap: Map<number, number>
   protected channelsMap: Map<number, number>
   protected videoIds: number[]
+  protected forcedChannelOwner: { id: string; controllerAccount: string } | undefined
 
-  public constructor({ api, queryNodeApi, config, videoIds, categoriesMap, channelsMap }: VideosMigrationParams) {
+  public constructor({ api, queryNodeApi, config, videoIds, channelsMap, forcedChannelOwner }: VideosMigrationParams) {
     super({ api, queryNodeApi, config })
     this.config = config
-    this.categoriesMap = categoriesMap
     this.channelsMap = channelsMap
     this.videoIds = videoIds
-  }
-
-  private getNewCategoryId(oldCategoryId: string | null | undefined): Long | undefined {
-    if (typeof oldCategoryId !== 'string') {
-      return undefined
-    }
-    const newCategoryId = this.categoriesMap.get(parseInt(oldCategoryId))
-    return newCategoryId ? Long.fromNumber(newCategoryId) : undefined
+    this.forcedChannelOwner = forcedChannelOwner
   }
 
   private getNewChannelId(oldChannelId: number): number {
@@ -119,8 +111,8 @@ export class VideosMigration extends AssetsMigration {
     }
 
     let { ownerMember } = channel
-    if (this.config.dev) {
-      ownerMember = { id: '0', controllerAccount: '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY' }
+    if (this.forcedChannelOwner) {
+      ownerMember = this.forcedChannelOwner
     }
 
     return { ...video, channel: { ...channel, ownerMember } }
@@ -156,7 +148,7 @@ export class VideosMigration extends AssetsMigration {
     const meta = new VideoMetadata({
       title,
       description,
-      category: this.getNewCategoryId(categoryId),
+      category: categoryId ? Long.fromString(categoryId) : undefined,
       duration,
       hasMarketing,
       isExplicit,