From 7c3c49913b99b1e729a5ee9104158d36f0613038 Mon Sep 17 00:00:00 2001 From: shafeeqd959 Date: Wed, 5 Jun 2024 20:18:44 +0530 Subject: [PATCH 1/2] fixed entry variant import for file fields and fixed project name duplication error --- .../src/utils/asset-helper.ts | 34 ++++++------- .../src/export/variant-entries.ts | 2 +- .../src/import/project.ts | 49 +++++++++++-------- .../src/import/variant-entries.ts | 47 ++++++++++++++++-- .../contentstack-variants/src/utils/helper.ts | 47 +++++++++++------- 5 files changed, 116 insertions(+), 63 deletions(-) diff --git a/packages/contentstack-import/src/utils/asset-helper.ts b/packages/contentstack-import/src/utils/asset-helper.ts index 5b9382f9e4..0608fd02eb 100644 --- a/packages/contentstack-import/src/utils/asset-helper.ts +++ b/packages/contentstack-import/src/utils/asset-helper.ts @@ -373,7 +373,7 @@ function findFileUrls(schema: any, _entry: any, assetUrls: any) { } function updateFileFields( - objekt: any, + object: any, parent: any, pos: any, mappedAssetUids: any, @@ -381,16 +381,16 @@ function updateFileFields( unmatchedUids: any, mappedAssetUrls?: any, ) { - if (_.isPlainObject(objekt) && _.has(objekt, 'filename') && _.has(objekt, 'uid')) { + if (_.isPlainObject(object) && _.has(object, 'filename') && _.has(object, 'uid')) { if (typeof pos !== 'undefined') { if (typeof pos === 'number' || typeof pos === 'string') { const replacer = () => { - if (mappedAssetUids.hasOwnProperty(objekt.uid)) { - parent[pos] = mappedAssetUids[objekt.uid]; - matchedUids.push(objekt.uid); + if (mappedAssetUids.hasOwnProperty(object.uid)) { + parent[pos] = mappedAssetUids[object.uid]; + matchedUids.push(object.uid); } else { parent[pos] = ''; - unmatchedUids.push(objekt.uid); + unmatchedUids.push(object.uid); } }; @@ -399,7 +399,7 @@ function updateFileFields( } if ( - objekt && + object && _.isObject(parent[pos]) && parent[pos].uid && parent[pos].url && @@ -415,23 +415,23 @@ function updateFileFields( parent = _.omit(parent, ['asset']); } - if (objekt.uid && mappedAssetUids && mappedAssetUids[objekt.uid]) { - objekt.uid = mappedAssetUids[objekt.uid]; + if (object.uid && mappedAssetUids && mappedAssetUids[object.uid]) { + object.uid = mappedAssetUids[object.uid]; } - if (objekt.url && mappedAssetUrls && mappedAssetUrls[objekt.url]) { - objekt.url = mappedAssetUrls[objekt.url]; + if (object.url && mappedAssetUrls && mappedAssetUrls[object.url]) { + object.url = mappedAssetUrls[object.url]; } } else { replacer(); } } } - } else if (_.isPlainObject(objekt)) { - for (let key in objekt) updateFileFields(objekt[key], objekt, key, mappedAssetUids, matchedUids, unmatchedUids); - } else if (_.isArray(objekt) && objekt.length) { - for (let i = 0; i <= objekt.length; i++) - updateFileFields(objekt[i], objekt, i, mappedAssetUids, matchedUids, unmatchedUids); + } else if (_.isPlainObject(object)) { + for (let key in object) updateFileFields(object[key], object, key, mappedAssetUids, matchedUids, unmatchedUids); + } else if (_.isArray(object) && object.length) { + for (let i = 0; i <= object.length; i++) + updateFileFields(object[i], object, i, mappedAssetUids, matchedUids, unmatchedUids); - parent[pos] = _.compact(objekt); + parent[pos] = _.compact(object); } } diff --git a/packages/contentstack-variants/src/export/variant-entries.ts b/packages/contentstack-variants/src/export/variant-entries.ts index 1a3ba00607..54873ed88e 100644 --- a/packages/contentstack-variants/src/export/variant-entries.ts +++ b/packages/contentstack-variants/src/export/variant-entries.ts @@ -67,7 +67,7 @@ export default class VariantEntries extends VariantAdapter { @@ -24,29 +24,36 @@ export default class Project extends PersonalizationAdapter { const projectPath = join(this.config.data, personalization.dirName, dirName, fileName); if (existsSync(projectPath)) { - try { - const projects = JSON.parse(readFileSync(projectPath, 'utf8')) as CreateProjectInput[]; - - if (!projects || projects.length < 1) { - this.config.modules.personalization.importData = false; // Stop personalization import if stack not connected to any project - this.log(this.config, 'No project found!', 'info'); - return; - } - - for (const project of projects) { - const { name, description } = project; - const projectRes = await this.createProject({ - name: `Copy of ${name}`, - description, + const projects = JSON.parse(readFileSync(projectPath, 'utf8')) as CreateProjectInput[]; + + if (!projects || projects.length < 1) { + this.config.modules.personalization.importData = false; // Stop personalization import if stack not connected to any project + this.log(this.config, 'No project found!', 'info'); + return; + } + + for (const project of projects) { + let projectRes: any; + const createProject = async (newName: void | string) => { + projectRes = await this.createProject({ + name: newName || project.name, + description: project.description, connectedStackApiKey: this.config.apiKey, + }).catch(async (error) => { + if (error === 'personalization.PROJECTS.DUPLICATE_NAME') { + const projectName = await askProjectName('Copy Of ' + (newName || project.name)); + return await createProject(projectName); + } + this.log(this.config, this.$t(this.messages.CREATE_FAILURE, { module: 'Projects' }), 'error'); + throw error; }); - this.config.modules.personalization.project_id = projectRes?.uid; - } + }; + + await createProject(); + + this.config.modules.personalization.project_id = projectRes.uid; this.config.modules.personalization.importData = true; - this.log(this.config, this.$t(this.messages.CREATE_SUCCESS, { module: 'Projects' }), 'info'); - } catch (error) { - this.log(this.config, this.$t(this.messages.CREATE_FAILURE, { module: 'Projects' }), 'error'); - throw error; + this.log(this.config, `Project Created Successfully: ${projectRes.uid}`, 'info'); } } else { this.config.modules.personalization.importData = false; // Stop personalization import if stack not connected to any project diff --git a/packages/contentstack-variants/src/import/variant-entries.ts b/packages/contentstack-variants/src/import/variant-entries.ts index d43ccadf60..6a616288ab 100644 --- a/packages/contentstack-variants/src/import/variant-entries.ts +++ b/packages/contentstack-variants/src/import/variant-entries.ts @@ -22,7 +22,7 @@ import { CreateVariantEntryDto, PublishVariantEntryDto, } from '../types'; -import { fsUtil, log } from '../utils'; +import { formatError, fsUtil, log } from '../utils'; export default class VariantEntries extends VariantAdapter> { public entriesDirPath: string; @@ -254,9 +254,10 @@ export default class VariantEntries extends VariantAdapter = {}; if (variantEntry?._variant?._change_set?.length) { - variantEntry._variant._change_set.forEach((data: string) => { - if (variantEntry[data]) { - changeSet[data] = variantEntry[data]; + variantEntry._variant._change_set.forEach((key: string) => { + key = key.split('.')[0]; + if (variantEntry[key]) { + changeSet[key] = variantEntry[key]; } }); } @@ -315,6 +316,9 @@ export default class VariantEntries extends VariantAdapter) => { + if (!currentObj || keys.length === 0) return; + + const [firstKey, ...restKeys] = keys; + + if (Array.isArray(currentObj)) { + for (const item of currentObj) { + setValue(item, [firstKey, ...restKeys]); + } + } else if (currentObj && typeof currentObj === 'object') { + if (firstKey in currentObj) { + if (keys.length === 1) { + currentObj[firstKey] = { uid: currentObj[firstKey], filename: 'dummy.jpeg' }; + } else { + setValue(currentObj[firstKey], restKeys); + } + } + } + }; + + const pathsToUpdate = variantEntry._metadata.references + .filter((ref: any) => ref._content_type_uid === 'sys_assets') + .map((ref: any) => ref.path); + + pathsToUpdate.forEach((path: string) => setValue(variantEntry, path.split('.'))); + } + /** * Publishes variant entries in batch for a given entry UID and content type. * @param batch - An array of VariantEntryStruct objects representing the variant entries to be published. @@ -373,7 +410,7 @@ export default class VariantEntries extends VariantAdapter { log(this.config, `Failed to publish entry variant: '${variantUid}' of entry uid ${entryUid}`, 'error'); - log(this.config, error, 'error'); + log(this.config, formatError(error), 'error'); }; const { environments, locales } = this.serializePublishEntries(variantEntry); diff --git a/packages/contentstack-variants/src/utils/helper.ts b/packages/contentstack-variants/src/utils/helper.ts index 6c8ffd74af..46802e2377 100644 --- a/packages/contentstack-variants/src/utils/helper.ts +++ b/packages/contentstack-variants/src/utils/helper.ts @@ -1,25 +1,34 @@ -import { FsUtility } from '@contentstack/cli-utilities'; +import { FsUtility, cliux } from '@contentstack/cli-utilities'; export const formatError = function (error: any) { - try { - if (typeof error === 'string') { - error = JSON.parse(error); - } else { - error = JSON.parse(error.message); - } - } catch (e) {} - let message = error.errorMessage || error.error_message || error.message || error; - if (error.errors && Object.keys(error.errors).length > 0) { - Object.keys(error.errors).forEach((e) => { - let entity = e; - if (e === 'authorization') entity = 'Management Token'; - if (e === 'api_key') entity = 'Stack API key'; - if (e === 'uid') entity = 'Content Type'; - if (e === 'access_token') entity = 'Delivery Token'; - message += ' ' + [entity, error.errors[e]].join(' '); - }); + try { + if (typeof error === 'string') { + error = JSON.parse(error); + } else { + error = JSON.parse(error.message); } - return message; + } catch (e) {} + let message = error.errorMessage || error.error_message || error.message || error; + if (error.errors && Object.keys(error.errors).length > 0) { + Object.keys(error.errors).forEach((e) => { + let entity = e; + if (e === 'authorization') entity = 'Management Token'; + if (e === 'api_key') entity = 'Stack API key'; + if (e === 'uid') entity = 'Content Type'; + if (e === 'access_token') entity = 'Delivery Token'; + message += ' ' + [entity, error.errors[e]].join(' '); + }); + } + return message; }; export const fsUtil = new FsUtility(); + +export const askProjectName = async (defaultValue: unknown): Promise => { + return await cliux.inquire({ + type: 'input', + name: 'name', + default: defaultValue, + message: 'Enter the project name:', + }); +}; From b36ce33cb77de5443d296b61a24593b02c24bfae Mon Sep 17 00:00:00 2001 From: shafeeqd959 Date: Thu, 6 Jun 2024 13:30:47 +0530 Subject: [PATCH 2/2] added project flag --- .../src/commands/cm/stacks/import.ts | 4 ++++ .../contentstack-import/src/types/import-config.ts | 1 + .../src/utils/import-config-handler.ts | 11 +++++------ packages/contentstack-variants/src/import/project.ts | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/contentstack-import/src/commands/cm/stacks/import.ts b/packages/contentstack-import/src/commands/cm/stacks/import.ts index abfb3ae45d..c01327d9d6 100644 --- a/packages/contentstack-import/src/commands/cm/stacks/import.ts +++ b/packages/contentstack-import/src/commands/cm/stacks/import.ts @@ -106,6 +106,10 @@ export default class ImportCommand extends Command { default: false, description: 'Skips the module exists warning messages.', }), + 'personalize-project-name': flags.string({ + required: false, + description: 'Personalize project name.', + }), 'skip-audit': flags.boolean({ description: 'Skips the audit fix.', }), diff --git a/packages/contentstack-import/src/types/import-config.ts b/packages/contentstack-import/src/types/import-config.ts index 0de52bf673..d6b1407366 100644 --- a/packages/contentstack-import/src/types/import-config.ts +++ b/packages/contentstack-import/src/types/import-config.ts @@ -50,6 +50,7 @@ export default interface ImportConfig extends DefaultConfig, ExternalConfig { skipAudit?: boolean; stackName?: string; region: Region; + personalizeProjectName?: string; } type branch = { diff --git a/packages/contentstack-import/src/utils/import-config-handler.ts b/packages/contentstack-import/src/utils/import-config-handler.ts index a3d5b8b333..1b55f7fb96 100644 --- a/packages/contentstack-import/src/utils/import-config-handler.ts +++ b/packages/contentstack-import/src/utils/import-config-handler.ts @@ -23,12 +23,9 @@ const setupConfig = async (importCmdFlags: any): Promise => { config.contentDir = importCmdFlags['data'] || importCmdFlags['data-dir'] || config.data || (await askContentDir()); const pattern = /[*$%#<>{}!&?]/g; if (pattern.test(config.contentDir)) { - cliux.print( - `\nPlease add a directory path without any of the special characters: (*,&,{,},[,],$,%,<,>,?,!)`, - { - color: 'yellow', - }, - ); + cliux.print(`\nPlease add a directory path without any of the special characters: (*,&,{,},[,],$,%,<,>,?,!)`, { + color: 'yellow', + }); config.contentDir = await askContentDir(); } config.contentDir = config.contentDir.replace(/['"]/g, ''); @@ -99,6 +96,8 @@ const setupConfig = async (importCmdFlags: any): Promise => { config.replaceExisting = importCmdFlags['replace-existing']; config.skipExisting = importCmdFlags['skip-existing']; + config.personalizeProjectName = importCmdFlags['personalize-project-name']; + return config; }; diff --git a/packages/contentstack-variants/src/import/project.ts b/packages/contentstack-variants/src/import/project.ts index 3d1bdaa00a..f53e2ea167 100644 --- a/packages/contentstack-variants/src/import/project.ts +++ b/packages/contentstack-variants/src/import/project.ts @@ -49,7 +49,7 @@ export default class Project extends PersonalizationAdapter { }); }; - await createProject(); + await createProject(this.config.personalizeProjectName); this.config.modules.personalization.project_id = projectRes.uid; this.config.modules.personalization.importData = true;