@contentstack/cli-variants 0.0.1-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/export/attributes.d.ts +15 -0
- package/lib/export/attributes.js +62 -0
- package/lib/export/audiences.d.ts +15 -0
- package/lib/export/audiences.js +63 -0
- package/lib/export/events.d.ts +15 -0
- package/lib/export/events.js +63 -0
- package/lib/export/experiences.d.ts +9 -0
- package/lib/export/experiences.js +99 -0
- package/lib/export/index.d.ts +9 -0
- package/lib/export/index.js +21 -0
- package/lib/export/projects.d.ts +9 -0
- package/lib/export/projects.js +73 -0
- package/lib/export/variant-entries.d.ts +18 -0
- package/lib/export/variant-entries.js +109 -0
- package/lib/import/attribute.d.ts +17 -0
- package/lib/import/attribute.js +64 -0
- package/lib/import/audiences.d.ts +19 -0
- package/lib/import/audiences.js +71 -0
- package/lib/import/events.d.ts +17 -0
- package/lib/import/events.js +62 -0
- package/lib/import/experiences.d.ts +46 -0
- package/lib/import/experiences.js +214 -0
- package/lib/import/index.d.ts +14 -0
- package/lib/import/index.js +21 -0
- package/lib/import/project.d.ts +13 -0
- package/lib/import/project.js +74 -0
- package/lib/import/variant-entries.d.ts +98 -0
- package/lib/import/variant-entries.js +407 -0
- package/lib/index.d.ts +5 -0
- package/lib/index.js +21 -0
- package/lib/messages/index.d.ts +35 -0
- package/lib/messages/index.js +55 -0
- package/lib/types/adapter-helper.d.ts +8 -0
- package/lib/types/adapter-helper.js +2 -0
- package/lib/types/content-types.d.ts +19 -0
- package/lib/types/content-types.js +2 -0
- package/lib/types/export-config.d.ts +264 -0
- package/lib/types/export-config.js +2 -0
- package/lib/types/import-config.d.ts +92 -0
- package/lib/types/import-config.js +2 -0
- package/lib/types/index.d.ts +8 -0
- package/lib/types/index.js +24 -0
- package/lib/types/personalization-api-adapter.d.ts +152 -0
- package/lib/types/personalization-api-adapter.js +2 -0
- package/lib/types/utils.d.ts +7 -0
- package/lib/types/utils.js +2 -0
- package/lib/types/variant-api-adapter.d.ts +49 -0
- package/lib/types/variant-api-adapter.js +2 -0
- package/lib/types/variant-entry.d.ts +47 -0
- package/lib/types/variant-entry.js +2 -0
- package/lib/utils/adapter-helper.d.ts +30 -0
- package/lib/utils/adapter-helper.js +95 -0
- package/lib/utils/attributes-helper.d.ts +7 -0
- package/lib/utils/attributes-helper.js +37 -0
- package/lib/utils/audiences-helper.d.ts +8 -0
- package/lib/utils/audiences-helper.js +49 -0
- package/lib/utils/error-helper.d.ts +6 -0
- package/lib/utils/error-helper.js +27 -0
- package/lib/utils/events-helper.d.ts +8 -0
- package/lib/utils/events-helper.js +27 -0
- package/lib/utils/helper.d.ts +4 -0
- package/lib/utils/helper.js +51 -0
- package/lib/utils/index.d.ts +9 -0
- package/lib/utils/index.js +25 -0
- package/lib/utils/logger.d.ts +3 -0
- package/lib/utils/logger.js +175 -0
- package/lib/utils/personalization-api-adapter.d.ts +73 -0
- package/lib/utils/personalization-api-adapter.js +184 -0
- package/lib/utils/variant-api-adapter.d.ts +79 -0
- package/lib/utils/variant-api-adapter.js +263 -0
- package/package.json +38 -0
- package/src/export/attributes.ts +55 -0
- package/src/export/audiences.ts +57 -0
- package/src/export/events.ts +57 -0
- package/src/export/experiences.ts +80 -0
- package/src/export/index.ts +11 -0
- package/src/export/projects.ts +45 -0
- package/src/export/variant-entries.ts +88 -0
- package/src/import/attribute.ts +60 -0
- package/src/import/audiences.ts +69 -0
- package/src/import/events.ts +58 -0
- package/src/import/experiences.ts +224 -0
- package/src/import/index.ts +16 -0
- package/src/import/project.ts +71 -0
- package/src/import/variant-entries.ts +483 -0
- package/src/index.ts +5 -0
- package/src/messages/index.ts +63 -0
- package/src/types/adapter-helper.ts +10 -0
- package/src/types/content-types.ts +41 -0
- package/src/types/export-config.ts +292 -0
- package/src/types/import-config.ts +95 -0
- package/src/types/index.ts +8 -0
- package/src/types/personalization-api-adapter.ts +197 -0
- package/src/types/utils.ts +8 -0
- package/src/types/variant-api-adapter.ts +56 -0
- package/src/types/variant-entry.ts +61 -0
- package/src/utils/adapter-helper.ts +79 -0
- package/src/utils/attributes-helper.ts +31 -0
- package/src/utils/audiences-helper.ts +50 -0
- package/src/utils/error-helper.ts +26 -0
- package/src/utils/events-helper.ts +26 -0
- package/src/utils/helper.ts +34 -0
- package/src/utils/index.ts +9 -0
- package/src/utils/logger.ts +160 -0
- package/src/utils/personalization-api-adapter.ts +188 -0
- package/src/utils/variant-api-adapter.ts +326 -0
- package/test/unit/export/variant-entries.test.ts +80 -0
- package/test/unit/import/variant-entries.test.ts +200 -0
- package/test/unit/mock/contents/content_types/CT-1.json +7 -0
- package/test/unit/mock/contents/entries/CT-1/en-us/variants/E-1/9b0da6xd7et72y-6gv7he23.json +12 -0
- package/test/unit/mock/contents/entries/CT-1/en-us/variants/E-1/index.json +3 -0
- package/test/unit/mock/contents/entries/CT-1/en-us/variants/E-2/9b0da6xd7et72y-6gv7he23.json +12 -0
- package/test/unit/mock/contents/entries/CT-1/en-us/variants/E-2/index.json +3 -0
- package/test/unit/mock/contents/mapper/assets/uid-mapping.json +6 -0
- package/test/unit/mock/contents/mapper/assets/url-mapping.json +6 -0
- package/test/unit/mock/contents/mapper/entries/data-for-variant-entry.json +6 -0
- package/test/unit/mock/contents/mapper/entries/empty-data/data-for-variant-entry.json +1 -0
- package/test/unit/mock/contents/mapper/entries/uid-mapping.json +6 -0
- package/test/unit/mock/contents/mapper/marketplace_apps/uid-mapping.json +3 -0
- package/test/unit/mock/contents/mapper/personalization/experiences/variants-uid-mapping.json +5 -0
- package/test/unit/mock/contents/mapper/taxonomies/terms/success.json +1 -0
- package/test/unit/mock/export-config.json +48 -0
- package/test/unit/mock/import-config.json +63 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { join, resolve } from 'path';
|
|
2
|
+
import { existsSync } from 'fs';
|
|
3
|
+
import values from 'lodash/values';
|
|
4
|
+
import cloneDeep from 'lodash/cloneDeep';
|
|
5
|
+
import { sanitizePath } from '@contentstack/cli-utilities';
|
|
6
|
+
import { PersonalizationAdapter, fsUtil, lookUpAudiences, lookUpEvents } from '../utils';
|
|
7
|
+
import { APIConfig, ImportConfig, ExperienceStruct, CreateExperienceInput, LogType } from '../types';
|
|
8
|
+
|
|
9
|
+
export default class Experiences extends PersonalizationAdapter<ImportConfig> {
|
|
10
|
+
private createdCTs: string[];
|
|
11
|
+
private mapperDirPath: string;
|
|
12
|
+
private cmsVariantPath: string;
|
|
13
|
+
private cTsSuccessPath: string;
|
|
14
|
+
private failedCmsExpPath: string;
|
|
15
|
+
private expMapperDirPath: string;
|
|
16
|
+
private eventsMapperPath: string;
|
|
17
|
+
private experiencesPath: string;
|
|
18
|
+
private experiencesDirPath: string;
|
|
19
|
+
private audiencesMapperPath: string;
|
|
20
|
+
private cmsVariantGroupPath: string;
|
|
21
|
+
private experienceVariantsIdsPath: string;
|
|
22
|
+
private variantUidMapperFilePath: string;
|
|
23
|
+
private expThresholdTimer: number;
|
|
24
|
+
private maxValidateRetry: number;
|
|
25
|
+
private experiencesUidMapperPath: string;
|
|
26
|
+
private experienceCTsPath: string;
|
|
27
|
+
private expCheckIntervalDuration: number;
|
|
28
|
+
private cmsVariants: Record<string, Record<string, string>>;
|
|
29
|
+
private cmsVariantGroups: Record<string, unknown>;
|
|
30
|
+
private experiencesUidMapper: Record<string, string>;
|
|
31
|
+
private pendingVariantAndVariantGrpForExperience: string[];
|
|
32
|
+
private personalizationConfig: ImportConfig['modules']['personalization'];
|
|
33
|
+
private audienceConfig: ImportConfig['modules']['personalization']['audiences'];
|
|
34
|
+
private experienceConfig: ImportConfig['modules']['personalization']['experiences'];
|
|
35
|
+
|
|
36
|
+
constructor(public readonly config: ImportConfig, private readonly log: LogType = console.log) {
|
|
37
|
+
const conf: APIConfig = {
|
|
38
|
+
config,
|
|
39
|
+
baseURL: config.modules.personalization.baseURL[config.region.name],
|
|
40
|
+
headers: { 'X-Project-Uid': config.modules.personalization.project_id, authtoken: config.auth_token },
|
|
41
|
+
cmaConfig: {
|
|
42
|
+
baseURL: config.region.cma + `/v3`,
|
|
43
|
+
headers: { authtoken: config.auth_token, api_key: config.apiKey },
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
super(Object.assign(config, conf));
|
|
47
|
+
this.personalizationConfig = this.config.modules.personalization;
|
|
48
|
+
this.experiencesDirPath = resolve(
|
|
49
|
+
sanitizePath(this.config.data),
|
|
50
|
+
sanitizePath(this.personalizationConfig.dirName),
|
|
51
|
+
sanitizePath(this.personalizationConfig.experiences.dirName),
|
|
52
|
+
);
|
|
53
|
+
this.experiencesPath = join(sanitizePath(this.experiencesDirPath), sanitizePath(this.personalizationConfig.experiences.fileName));
|
|
54
|
+
this.experienceConfig = this.personalizationConfig.experiences;
|
|
55
|
+
this.audienceConfig = this.personalizationConfig.audiences;
|
|
56
|
+
this.mapperDirPath = resolve(sanitizePath(this.config.backupDir), 'mapper', sanitizePath(this.personalizationConfig.dirName));
|
|
57
|
+
this.expMapperDirPath = resolve(sanitizePath(this.mapperDirPath), sanitizePath(this.experienceConfig.dirName));
|
|
58
|
+
this.experiencesUidMapperPath = resolve(sanitizePath(this.expMapperDirPath), 'uid-mapping.json');
|
|
59
|
+
this.cmsVariantGroupPath = resolve(sanitizePath(this.expMapperDirPath), 'cms-variant-groups.json');
|
|
60
|
+
this.cmsVariantPath = resolve(sanitizePath(this.expMapperDirPath), 'cms-variants.json');
|
|
61
|
+
this.audiencesMapperPath = resolve(sanitizePath(this.mapperDirPath), sanitizePath(this.audienceConfig.dirName), 'uid-mapping.json');
|
|
62
|
+
this.eventsMapperPath = resolve(sanitizePath(this.mapperDirPath), 'events', 'uid-mapping.json');
|
|
63
|
+
this.failedCmsExpPath = resolve(sanitizePath(this.expMapperDirPath), 'failed-cms-experience.json');
|
|
64
|
+
this.failedCmsExpPath = resolve(sanitizePath(this.expMapperDirPath), 'failed-cms-experience.json');
|
|
65
|
+
this.experienceCTsPath = resolve(sanitizePath(this.experiencesDirPath), 'experiences-content-types.json');
|
|
66
|
+
this.experienceVariantsIdsPath = resolve(
|
|
67
|
+
sanitizePath(this.config.data),
|
|
68
|
+
sanitizePath(this.personalizationConfig.dirName),
|
|
69
|
+
sanitizePath(this.experienceConfig.dirName),
|
|
70
|
+
'experiences-variants-ids.json',
|
|
71
|
+
);
|
|
72
|
+
this.variantUidMapperFilePath = resolve(sanitizePath(this.expMapperDirPath), 'variants-uid-mapping.json');
|
|
73
|
+
this.experiencesUidMapper = {};
|
|
74
|
+
this.cmsVariantGroups = {};
|
|
75
|
+
this.cmsVariants = {};
|
|
76
|
+
this.expThresholdTimer = this.experienceConfig?.thresholdTimer ?? 30000;
|
|
77
|
+
this.expCheckIntervalDuration = this.experienceConfig?.checkIntervalDuration ?? 5000;
|
|
78
|
+
this.maxValidateRetry = Math.round(this.expThresholdTimer / this.expCheckIntervalDuration);
|
|
79
|
+
this.pendingVariantAndVariantGrpForExperience = [];
|
|
80
|
+
this.cTsSuccessPath = resolve(sanitizePath(this.config.backupDir), 'mapper', 'content_types', 'success.json');
|
|
81
|
+
this.createdCTs = [];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The function asynchronously imports experiences from a JSON file and creates them in the system.
|
|
86
|
+
*/
|
|
87
|
+
async import() {
|
|
88
|
+
this.log(this.config, this.$t(this.messages.IMPORT_MSG, { module: 'Experiences' }), 'info');
|
|
89
|
+
|
|
90
|
+
await fsUtil.makeDirectory(this.expMapperDirPath);
|
|
91
|
+
|
|
92
|
+
if (existsSync(this.experiencesPath)) {
|
|
93
|
+
try {
|
|
94
|
+
const experiences = fsUtil.readFile(this.experiencesPath, true) as ExperienceStruct[];
|
|
95
|
+
const audiencesUid = (fsUtil.readFile(this.audiencesMapperPath, true) as Record<string, string>) || {};
|
|
96
|
+
const eventsUid = (fsUtil.readFile(this.eventsMapperPath, true) as Record<string, string>) || {};
|
|
97
|
+
|
|
98
|
+
for (const experience of experiences) {
|
|
99
|
+
const { uid, ...restExperienceData } = experience;
|
|
100
|
+
//check whether reference audience exists or not that referenced in variations having __type equal to AudienceBasedVariation & targeting
|
|
101
|
+
let experienceReqObj: CreateExperienceInput = lookUpAudiences(restExperienceData, audiencesUid);
|
|
102
|
+
//check whether events exists or not that referenced in metrics
|
|
103
|
+
experienceReqObj = lookUpEvents(experienceReqObj, eventsUid);
|
|
104
|
+
|
|
105
|
+
const expRes = await this.createExperience(experienceReqObj);
|
|
106
|
+
//map old experience uid to new experience uid
|
|
107
|
+
this.experiencesUidMapper[uid] = expRes?.uid ?? '';
|
|
108
|
+
}
|
|
109
|
+
fsUtil.writeFile(this.experiencesUidMapperPath, this.experiencesUidMapper);
|
|
110
|
+
this.log(this.config, this.$t(this.messages.CREATE_SUCCESS, { module: 'Experiences' }), 'info');
|
|
111
|
+
|
|
112
|
+
this.log(this.config, this.messages.VALIDATE_VARIANT_AND_VARIANT_GRP, 'info');
|
|
113
|
+
this.pendingVariantAndVariantGrpForExperience = values(cloneDeep(this.experiencesUidMapper));
|
|
114
|
+
const jobRes = await this.validateVariantGroupAndVariantsCreated();
|
|
115
|
+
fsUtil.writeFile(this.cmsVariantPath, this.cmsVariants);
|
|
116
|
+
fsUtil.writeFile(this.cmsVariantGroupPath, this.cmsVariantGroups);
|
|
117
|
+
if (jobRes)
|
|
118
|
+
this.log(this.config, this.$t(this.messages.CREATE_SUCCESS, { module: 'Variant & Variant groups' }), 'info');
|
|
119
|
+
|
|
120
|
+
if (this.personalizationConfig.importData) {
|
|
121
|
+
this.log(this.config, this.messages.UPDATING_CT_IN_EXP, 'info');
|
|
122
|
+
await this.attachCTsInExperience();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
await this.createVariantIdMapper();
|
|
126
|
+
} catch (error) {
|
|
127
|
+
this.log(this.config, this.$t(this.messages.CREATE_FAILURE, { module: 'Experiences' }), 'error');
|
|
128
|
+
this.log(this.config, error, 'error');
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* function to validate if all variant groups and variants have been created using personalization background job
|
|
135
|
+
* store the variant groups data in mapper/personalization/experiences/cms-variant-groups.json and the variants data
|
|
136
|
+
* in mapper/personalization/experiences/cms-variants.json. If not, invoke validateVariantGroupAndVariantsCreated after some delay.
|
|
137
|
+
* @param retryCount Counter to track the number of times the function has been called
|
|
138
|
+
* @returns
|
|
139
|
+
*/
|
|
140
|
+
async validateVariantGroupAndVariantsCreated(retryCount = 0): Promise<any> {
|
|
141
|
+
try {
|
|
142
|
+
const promises = this.pendingVariantAndVariantGrpForExperience.map(async (expUid) => {
|
|
143
|
+
const expRes = await this.getExperience(expUid);
|
|
144
|
+
if (expRes?._cms) {
|
|
145
|
+
this.cmsVariants[expUid] = expRes._cms?.variants ?? {};
|
|
146
|
+
this.cmsVariantGroups[expUid] = expRes._cms?.variantGroup ?? {};
|
|
147
|
+
return expUid; // Return the expUid for filtering later
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
await Promise.all(promises);
|
|
152
|
+
retryCount++;
|
|
153
|
+
|
|
154
|
+
if (this.pendingVariantAndVariantGrpForExperience?.length) {
|
|
155
|
+
if (retryCount !== this.maxValidateRetry) {
|
|
156
|
+
await this.delay(this.expCheckIntervalDuration);
|
|
157
|
+
// Filter out the processed elements
|
|
158
|
+
this.pendingVariantAndVariantGrpForExperience = this.pendingVariantAndVariantGrpForExperience.filter(
|
|
159
|
+
(uid) => !this.cmsVariants[uid],
|
|
160
|
+
);
|
|
161
|
+
return this.validateVariantGroupAndVariantsCreated(retryCount);
|
|
162
|
+
} else {
|
|
163
|
+
this.log(this.config, this.messages.PERSONALIZATION_JOB_FAILURE, 'error');
|
|
164
|
+
fsUtil.writeFile(this.failedCmsExpPath, this.pendingVariantAndVariantGrpForExperience);
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
} else {
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
} catch (error) {
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async attachCTsInExperience() {
|
|
176
|
+
try {
|
|
177
|
+
// Read the created content types from the file
|
|
178
|
+
this.createdCTs = fsUtil.readFile(this.cTsSuccessPath, true) as any;
|
|
179
|
+
if (!this.createdCTs) {
|
|
180
|
+
this.log(this.config, 'No Content types created, skipping following process', 'error');
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const experienceCTsMap = fsUtil.readFile(this.experienceCTsPath, true) as Record<string, string[]>;
|
|
184
|
+
return await Promise.allSettled(
|
|
185
|
+
Object.entries(this.experiencesUidMapper).map(async ([oldExpUid, newExpUid]) => {
|
|
186
|
+
if (experienceCTsMap[oldExpUid]?.length) {
|
|
187
|
+
// Filter content types that were created
|
|
188
|
+
const updatedContentTypes = experienceCTsMap[oldExpUid].filter((ct: any) =>
|
|
189
|
+
this.createdCTs.includes(ct?.uid),
|
|
190
|
+
);
|
|
191
|
+
if (updatedContentTypes?.length) {
|
|
192
|
+
const { variant_groups: [variantGroup] = [] } =
|
|
193
|
+
(await this.getVariantGroup({ experienceUid: newExpUid })) || {};
|
|
194
|
+
variantGroup.content_types = updatedContentTypes;
|
|
195
|
+
// Update content types detail in the new experience asynchronously
|
|
196
|
+
return await this.updateVariantGroup(variantGroup);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}),
|
|
200
|
+
);
|
|
201
|
+
} catch (error) {
|
|
202
|
+
this.log(this.config, `Error while attaching content type with experience`, 'error');
|
|
203
|
+
this.log(this.config, error, 'error');
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async createVariantIdMapper() {
|
|
208
|
+
try {
|
|
209
|
+
const experienceVariantIds: any = fsUtil.readFile(this.experienceVariantsIdsPath, true) || [];
|
|
210
|
+
const variantUIDMapper: Record<string, string> = {};
|
|
211
|
+
for (let experienceVariantId of experienceVariantIds) {
|
|
212
|
+
const [experienceId, variantShortId, oldVariantId] = experienceVariantId.split('-');
|
|
213
|
+
const latestVariantId = this.cmsVariants[this.experiencesUidMapper[experienceId]]?.[variantShortId];
|
|
214
|
+
if (latestVariantId) {
|
|
215
|
+
variantUIDMapper[oldVariantId] = latestVariantId;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
fsUtil.writeFile(this.variantUidMapperFilePath, variantUIDMapper);
|
|
220
|
+
} catch (error) {
|
|
221
|
+
throw error;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import Events from './events';
|
|
2
|
+
import Project from './project';
|
|
3
|
+
import Attribute from './attribute';
|
|
4
|
+
import Audiences from './audiences';
|
|
5
|
+
import Experiences from './experiences';
|
|
6
|
+
import VariantEntries from './variant-entries';
|
|
7
|
+
|
|
8
|
+
// NOTE Acting as namespace to avoid the same class name conflicts in other modules
|
|
9
|
+
export const Import = {
|
|
10
|
+
Events,
|
|
11
|
+
Project,
|
|
12
|
+
Attribute,
|
|
13
|
+
Audiences,
|
|
14
|
+
Experiences,
|
|
15
|
+
VariantEntries,
|
|
16
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { join, resolve as pResolve } from 'path';
|
|
2
|
+
import { existsSync, readFileSync } from 'fs';
|
|
3
|
+
import { sanitizePath } from '@contentstack/cli-utilities';
|
|
4
|
+
import { PersonalizationAdapter, askProjectName, fsUtil } from '../utils';
|
|
5
|
+
import { APIConfig, CreateProjectInput, ImportConfig, LogType, ProjectStruct } from '../types';
|
|
6
|
+
|
|
7
|
+
export default class Project extends PersonalizationAdapter<ImportConfig> {
|
|
8
|
+
private projectMapperFolderPath: string;
|
|
9
|
+
constructor(public readonly config: ImportConfig, private readonly log: LogType = console.log) {
|
|
10
|
+
const conf: APIConfig = {
|
|
11
|
+
config,
|
|
12
|
+
baseURL: config.modules.personalization.baseURL[config.region.name],
|
|
13
|
+
headers: { organization_uid: config.org_uid, authtoken: config.auth_token },
|
|
14
|
+
};
|
|
15
|
+
super(Object.assign(config, conf));
|
|
16
|
+
this.projectMapperFolderPath = pResolve(
|
|
17
|
+
sanitizePath(this.config.backupDir),
|
|
18
|
+
'mapper',
|
|
19
|
+
sanitizePath(this.config.modules.personalization.dirName),
|
|
20
|
+
'projects',
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The function asynchronously imports projects data from a file and creates projects based on the
|
|
26
|
+
* data.
|
|
27
|
+
*/
|
|
28
|
+
async import() {
|
|
29
|
+
const personalization = this.config.modules.personalization;
|
|
30
|
+
const { dirName, fileName } = personalization.projects;
|
|
31
|
+
const projectPath = join(sanitizePath(this.config.data), sanitizePath(personalization.dirName), sanitizePath(dirName), sanitizePath(fileName));
|
|
32
|
+
|
|
33
|
+
if (existsSync(projectPath)) {
|
|
34
|
+
const projects = JSON.parse(readFileSync(projectPath, 'utf8')) as CreateProjectInput[];
|
|
35
|
+
|
|
36
|
+
if (!projects || projects.length < 1) {
|
|
37
|
+
this.config.modules.personalization.importData = false; // Stop personalization import if stack not connected to any project
|
|
38
|
+
this.log(this.config, 'No project found!', 'info');
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
for (const project of projects) {
|
|
43
|
+
const createProject = async (newName: void | string): Promise<ProjectStruct> => {
|
|
44
|
+
return await this.createProject({
|
|
45
|
+
name: newName || project.name,
|
|
46
|
+
description: project.description,
|
|
47
|
+
connectedStackApiKey: this.config.apiKey,
|
|
48
|
+
}).catch(async (error) => {
|
|
49
|
+
if (error === 'personalization.PROJECTS.DUPLICATE_NAME') {
|
|
50
|
+
const projectName = await askProjectName('Copy Of ' + (newName || project.name));
|
|
51
|
+
return await createProject(projectName);
|
|
52
|
+
}
|
|
53
|
+
this.log(this.config, this.$t(this.messages.CREATE_FAILURE, { module: 'Projects' }), 'error');
|
|
54
|
+
throw error;
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const projectRes = await createProject(this.config.personalizeProjectName);
|
|
59
|
+
this.config.modules.personalization.project_id = projectRes.uid;
|
|
60
|
+
this.config.modules.personalization.importData = true;
|
|
61
|
+
|
|
62
|
+
await fsUtil.makeDirectory(this.projectMapperFolderPath);
|
|
63
|
+
fsUtil.writeFile(pResolve(sanitizePath(this.projectMapperFolderPath), 'projects.json'), projectRes);
|
|
64
|
+
this.log(this.config, `Project Created Successfully: ${projectRes.uid}`, 'info');
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
this.config.modules.personalization.importData = false; // Stop personalization import if stack not connected to any project
|
|
68
|
+
this.log(this.config, 'No project found!', 'info');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|