From 01c22f6430a617dd185617cf47a8f42ca47976c3 Mon Sep 17 00:00:00 2001 From: Jan Cerman Date: Mon, 24 Jun 2024 15:06:25 +0200 Subject: [PATCH] CTC-2272 Add migration examples --- .../install_migration_toolkit.sh | 2 + .../migration_toolkit_boilerplate | 36 +++++++++ .../migration_toolkit_map_migrationasset.ts | 45 +++++++++++ .../migration_toolkit_map_migrationitem.ts | 81 +++++++++++++++++++ 4 files changed, 164 insertions(+) create mode 100644 ts/migrate-from-other-systems/install_migration_toolkit.sh create mode 100644 ts/migrate-from-other-systems/migration_toolkit_boilerplate create mode 100644 ts/migrate-from-other-systems/migration_toolkit_map_migrationasset.ts create mode 100644 ts/migrate-from-other-systems/migration_toolkit_map_migrationitem.ts diff --git a/ts/migrate-from-other-systems/install_migration_toolkit.sh b/ts/migrate-from-other-systems/install_migration_toolkit.sh new file mode 100644 index 00000000..55639677 --- /dev/null +++ b/ts/migrate-from-other-systems/install_migration_toolkit.sh @@ -0,0 +1,2 @@ +# Add the Migration toolkit to your migration project +npm i @kontent-ai-consulting/migration-toolkit --save-dev \ No newline at end of file diff --git a/ts/migrate-from-other-systems/migration_toolkit_boilerplate b/ts/migrate-from-other-systems/migration_toolkit_boilerplate new file mode 100644 index 00000000..f651e501 --- /dev/null +++ b/ts/migrate-from-other-systems/migration_toolkit_boilerplate @@ -0,0 +1,36 @@ +import { + ExportAdapter, + MigrationAsset, + MigrationItem, + exportAsync, + importAsync, +} from "@kontent-ai-consulting/migration-toolkit"; + +// Specifies how to map the exported content to migration objects +const adapter: ExportAdapter = { + name: "customExportAdapter", + exportAsync: () => { + // TODO: Load the exported content and map it to MigrationItems + const migrationItems: MigrationItem[] = []; + // TODO: Load the exported assets and map them to MigrationAssets + const migrationAssets: MigrationAsset[] = []; + + return { + items: migrationItems, + assets: migrationAssets, + }; + }, +}; + +// Runs the adapter to prepare exported data for import +const exportData = await exportAsync(adapter); + +// Imports the exported data to a Kontent.ai environment +await importAsync({ + data: exportData, + adapterConfig: { + environmentId: "YOUR_ENVIRONMENT_ID", + apiKey: "YOUR_MANAGEMENT_API_KEY", + skipFailedItems: false, + }, +}); \ No newline at end of file diff --git a/ts/migrate-from-other-systems/migration_toolkit_map_migrationasset.ts b/ts/migrate-from-other-systems/migration_toolkit_map_migrationasset.ts new file mode 100644 index 00000000..5c150384 --- /dev/null +++ b/ts/migrate-from-other-systems/migration_toolkit_map_migrationasset.ts @@ -0,0 +1,45 @@ +import { + MigrationAsset, + ExportAdapter, +} from "@kontent-ai-consulting/migration-toolkit"; +import { readFileSync } from "fs"; + +// Adapter specifies how to map the exported content to migration objects +const adapter: ExportAdapter = { + name: "customExportAdapter", + exportAsync: () => { + const sourceAssets = readFileSync("./exported-files.zip"); + const migrationAssets: MigrationAsset[] = []; + + // Example of mapping exported files to an MigrationAsset + for (const sourceAsset of JSON.parse(sourceAssets)) { + const asset: MigrationAsset = { + // Identifies a file within the exported .zip archive + _zipFilename: sourceAsset.filename, + // Specifies the asset filename to use in Kontent.ai + codename: toCodename(sourceAsset.filename), + filename: sourceAsset.filename, + // Specifies the asset title. + title: sourceAsset.title, + // Specifies the binary file you want to upload and use for the asset + binaryData: readFileSync("./warrior_teaser.jpg"), // TBD + // Specifies alt texts for the asset in multiple languages + descriptions: [ + { + description: sourceAsset.altText, + language: { + codename: toLanguage(sourceAsset.altTextLanguage) + } + } + ] + }; + + migrationAssets.push(asset); + } + + return { + assets: migrationAssets, + }; + }, +}; + diff --git a/ts/migrate-from-other-systems/migration_toolkit_map_migrationitem.ts b/ts/migrate-from-other-systems/migration_toolkit_map_migrationitem.ts new file mode 100644 index 00000000..06cac82a --- /dev/null +++ b/ts/migrate-from-other-systems/migration_toolkit_map_migrationitem.ts @@ -0,0 +1,81 @@ +import { + MigrationElementModels, + MigrationElements, + MigrationItem, + elementsBuilder, + ExportAdapter, +} from "@kontent-ai-consulting/migration-toolkit"; +import { readFileSync } from "fs"; + +// Defines the elements of the Movie content type in a Kontent.ai project +interface MovieElements extends MigrationElements { + title: MigrationElementModels.TextElement; + plot: MigrationElementModels.RichTextElement; + length: MigrationElementModels.NumberElement; + category: MigrationElementModels.MultipleChoiceElement; + poster: MigrationElementModels.AssetElement; +} + +// Defines the structure of the exported content for easier mapping +interface SourceItemModel { + title: string; + language: string; + genre: string; + text: string; + duration: number; +} + +// Adapter specifies how to map the exported content to migration objects +const adapter: ExportAdapter = { + name: "customExportAdapter", + exportAsync: () => { + // Load the exported content to 'fileData' + const sourceContent = readFileSync("./exported-content.json").toString(); + const migrationItems: MigrationItem[] = []; + + // Example of mapping a source item to a typed MigrationItem + for (const item of JSON.parse(sourceContent) as SourceItemModel[]) { + const movie: MigrationItem = { + system: { + name: item.title, + // TODO: Write a custom function to transform the original title to the Kontent.ai codename format according to https://kontent.ai/learn/docs/apis/openapi/management-api-v2/#section/Rules-for-codenames + codename: toCodename(item.title), + collection: { codename: "default", }, + // TODO: Write a custom function to transform the source language identifier to your language codename in Kontent.ai + language: { codename: toLanguage(item.language), }, + // Because we're migrating a single type of content, cotent type codename is hardcoded + type: { codename: "movie", }, + workflow: { codename: "default", }, + workflow_step: { codename: "draft", }, + }, + elements: { + title: elementsBuilder().textElement({ value: item.title }), + length: elementsBuilder().numberElement({ value: item.duration }), + category: elementsBuilder().multipleChoiceElement({ + value: item.genre.split(",").map((m) => { + return { codename: m.trim() }; + }), + }), + // Asset element references the file by the asset codename + poster: elementsBuilder().assetElement({ + value: [{ codename: "warrior_teaser", },], + }), + // The rich text content in Kontent.ai is an HTML5 fragment that contains structured content + // See https://kontent.ai/learn/docs/apis/openapi/management-api-v2/#section/HTML5-elements-allowed-in-rich-text + plot: elementsBuilder().richTextElement({ + value: { + value: `

${item.title}

${item.text}

`, + components: [], + }, + }), + }, + }; + + migrationItems.push(movie); + } + + return { + items: migrationItems, + }; + }, +}; \ No newline at end of file