@contentstack/cli-cm-import 1.7.0 → 1.8.0
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/README.md +1 -1
- package/lib/config/index.js +2 -0
- package/lib/import/module-importer.js +15 -0
- package/lib/import/modules/base-class.d.ts +1 -1
- package/lib/import/modules/base-class.js +31 -1
- package/lib/import/modules/content-types.js +1 -1
- package/lib/import/modules/entries.d.ts +93 -0
- package/lib/import/modules/entries.js +536 -0
- package/lib/import/modules/marketplace-apps.d.ts +5 -2
- package/lib/import/modules/marketplace-apps.js +34 -17
- package/lib/import/modules/workflows.d.ts +41 -0
- package/lib/import/modules/workflows.js +209 -0
- package/lib/import/modules-js/custom-roles.js +1 -1
- package/lib/import/modules-js/entries.js +20 -8
- package/lib/import/modules-js/environments.js +1 -1
- package/lib/import/modules-js/extensions.js +1 -1
- package/lib/import/modules-js/global-fields.js +2 -4
- package/lib/import/modules-js/marketplace-apps.d.ts +6 -4
- package/lib/import/modules-js/marketplace-apps.js +29 -25
- package/lib/import/modules-js/workflows.js +2 -2
- package/lib/types/default-config.d.ts +1 -0
- package/lib/utils/asset-helper.d.ts +1 -1
- package/lib/utils/backup-handler.js +10 -1
- package/lib/utils/entries-helper.d.ts +4 -1
- package/lib/utils/entries-helper.js +322 -2
- package/lib/utils/file-helper.d.ts +1 -0
- package/lib/utils/file-helper.js +5 -1
- package/lib/utils/import-config-handler.js +1 -1
- package/lib/utils/index.d.ts +2 -2
- package/lib/utils/index.js +4 -1
- package/oclif.manifest.json +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* eslint-disable no-prototype-builtins */
|
|
3
|
+
/*!
|
|
4
|
+
* Contentstack Import
|
|
5
|
+
* Copyright (c) 2019 Contentstack LLC
|
|
6
|
+
* MIT Licensed
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
const tslib_1 = require("tslib");
|
|
10
|
+
const path = tslib_1.__importStar(require("path"));
|
|
11
|
+
const lodash_1 = require("lodash");
|
|
12
|
+
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
13
|
+
const utils_1 = require("../../utils");
|
|
14
|
+
const base_class_1 = tslib_1.__importDefault(require("./base-class"));
|
|
15
|
+
class EntriesImport extends base_class_1.default {
|
|
16
|
+
constructor({ importConfig, stackAPIClient }) {
|
|
17
|
+
super({ importConfig, stackAPIClient });
|
|
18
|
+
this.assetUidMapperPath = path.resolve(importConfig.data, 'mapper', 'assets', 'uid-mapping.json');
|
|
19
|
+
this.assetUrlMapperPath = path.resolve(importConfig.data, 'mapper', 'assets', 'url-mapping.json');
|
|
20
|
+
this.entriesMapperPath = path.resolve(importConfig.data, 'mapper', 'entries');
|
|
21
|
+
this.envPath = path.resolve(importConfig.data, 'environments', 'environments.json');
|
|
22
|
+
this.entriesUIDMapperPath = path.join(this.entriesMapperPath, 'uid-mapping.json');
|
|
23
|
+
this.uniqueUidMapperPath = path.join(this.entriesMapperPath, 'unique-mapping.json');
|
|
24
|
+
this.modifiedCTsPath = path.join(this.entriesMapperPath, 'modified-schemas.json');
|
|
25
|
+
this.marketplaceAppMapperPath = path.join(this.importConfig.data, 'mapper', 'marketplace_apps', 'uid-mapping.json');
|
|
26
|
+
this.entriesConfig = importConfig.modules.entries;
|
|
27
|
+
this.entriesPath = path.resolve(importConfig.data, this.entriesConfig.dirName);
|
|
28
|
+
this.cTsPath = path.resolve(importConfig.data, importConfig.modules['content-types'].dirName);
|
|
29
|
+
this.localesPath = path.resolve(importConfig.data, importConfig.modules.locales.dirName, importConfig.modules.locales.fileName);
|
|
30
|
+
this.importConcurrency = this.entriesConfig.importConcurrency || importConfig.importConcurrency;
|
|
31
|
+
this.entriesUidMapper = {};
|
|
32
|
+
this.modifiedCTs = [];
|
|
33
|
+
this.refCTs = [];
|
|
34
|
+
this.jsonRteCTs = [];
|
|
35
|
+
this.jsonRteCTsWithRef = [];
|
|
36
|
+
this.envs = {};
|
|
37
|
+
this.autoCreatedEntries = [];
|
|
38
|
+
}
|
|
39
|
+
async start() {
|
|
40
|
+
try {
|
|
41
|
+
this.cTs = utils_1.fsUtil.readFile(path.join(this.cTsPath, 'schema.json'));
|
|
42
|
+
if (!this.cTs || (0, lodash_1.isEmpty)(this.cTs)) {
|
|
43
|
+
(0, utils_1.log)(this.importConfig, 'No content type found', 'info');
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
this.installedExtensions = ((await utils_1.fsUtil.readFile(this.marketplaceAppMapperPath)) || { extension_uid: {} }).extension_uid;
|
|
47
|
+
this.assetUidMapper = utils_1.fsUtil.readFile(this.assetUidMapperPath) || {};
|
|
48
|
+
this.assetUrlMapper = utils_1.fsUtil.readFile(this.assetUrlMapperPath) || {};
|
|
49
|
+
utils_1.fsUtil.makeDirectory(this.entriesMapperPath);
|
|
50
|
+
await this.disableMandatoryCTReferences();
|
|
51
|
+
this.locales = (0, lodash_1.values)(utils_1.fsUtil.readFile(this.localesPath));
|
|
52
|
+
this.locales.unshift(this.importConfig.master_locale); // adds master locale to the list
|
|
53
|
+
//Create Entries
|
|
54
|
+
const entryRequestOptions = this.populateEntryCreatePayload();
|
|
55
|
+
for (let entryRequestOption of entryRequestOptions) {
|
|
56
|
+
await this.createEntries(entryRequestOption);
|
|
57
|
+
}
|
|
58
|
+
await utils_1.fileHelper.writeLargeFile(path.join(this.entriesMapperPath, 'uid-mapping.json'), this.entriesUidMapper); // TBD: manages mapper in one file, should find an alternative
|
|
59
|
+
utils_1.fsUtil.writeFile(path.join(this.entriesMapperPath, 'failed-entries.json'), this.failedEntries);
|
|
60
|
+
// Update entries with references
|
|
61
|
+
const entryUpdateRequestOptions = this.populateEntryUpdatePayload();
|
|
62
|
+
for (let entryUpdateRequestOption of entryUpdateRequestOptions) {
|
|
63
|
+
await this.updateEntriesWithReferences(entryUpdateRequestOption).catch((error) => {
|
|
64
|
+
(0, utils_1.log)(this.importConfig, `Error while updating entries references of ${entryUpdateRequestOption.cTUid} in locale ${entryUpdateRequestOption.locale}`, 'error');
|
|
65
|
+
(0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
utils_1.fsUtil.writeFile(path.join(this.entriesMapperPath, 'failed-entries.json'), this.failedEntries);
|
|
69
|
+
(0, utils_1.log)(this.importConfig, 'Restoring content type changes', 'info');
|
|
70
|
+
await this.enableMandatoryCTReferences().catch((error) => {
|
|
71
|
+
(0, utils_1.log)(this.importConfig, `Error while updating content type references ${(0, utils_1.formatError)(error)}`, 'error');
|
|
72
|
+
});
|
|
73
|
+
if (this.autoCreatedEntries.length > 0) {
|
|
74
|
+
(0, utils_1.log)(this.importConfig, 'Removing entries from master language which got created by default', 'info');
|
|
75
|
+
await this.removeAutoCreatedEntries().catch((error) => {
|
|
76
|
+
(0, utils_1.log)(this.importConfig, `Error while removing auto created entries in master locale ${(0, utils_1.formatError)(error)}`, 'error');
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
// Update field rule of content types which are got removed earlier
|
|
80
|
+
(0, utils_1.log)(this.importConfig, 'Updating the field rules of content type', 'info');
|
|
81
|
+
await this.updateFieldRules().catch((error) => {
|
|
82
|
+
(0, utils_1.log)(this.importConfig, `Error while updating field rules of content type ${(0, utils_1.formatError)(error)}`, 'error');
|
|
83
|
+
});
|
|
84
|
+
(0, utils_1.log)(this.importConfig, 'Entries imported successfully', 'success');
|
|
85
|
+
// Publishing entries
|
|
86
|
+
if (this.importConfig.entriesPublish) {
|
|
87
|
+
(0, utils_1.log)(this.importConfig, 'Publishing entries', 'info');
|
|
88
|
+
this.envs = utils_1.fileHelper.readFileSync(this.envPath);
|
|
89
|
+
for (let entryRequestOption of entryRequestOptions) {
|
|
90
|
+
await this.publishEntries(entryRequestOption).catch((error) => {
|
|
91
|
+
(0, utils_1.log)(this.importConfig, `Error in publishing entries of ${entryRequestOption.cTUid} in locale ${entryRequestOption.locale} ${(0, utils_1.formatError)(error)}`, 'error');
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
(0, utils_1.log)(this.importConfig, 'All the entries have been published successfully', 'success');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
(0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
|
|
99
|
+
throw new Error('Error while importing entries');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async disableMandatoryCTReferences() {
|
|
103
|
+
const onSuccess = ({ response: contentType, apiData: { uid } }) => {
|
|
104
|
+
(0, utils_1.log)(this.importConfig, `${uid} content type references removed temporarily`, 'success');
|
|
105
|
+
};
|
|
106
|
+
const onReject = ({ error, apiData: { uid } }) => {
|
|
107
|
+
(0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
|
|
108
|
+
throw new Error(`${uid} content type references removal failed`);
|
|
109
|
+
};
|
|
110
|
+
return await this.makeConcurrentCall({
|
|
111
|
+
processName: 'Update content types (removing mandatory references temporarily)',
|
|
112
|
+
apiContent: this.cTs,
|
|
113
|
+
apiParams: {
|
|
114
|
+
serializeData: this.serializeUpdateCTs.bind(this),
|
|
115
|
+
reject: onReject.bind(this),
|
|
116
|
+
resolve: onSuccess.bind(this),
|
|
117
|
+
entity: 'update-cts',
|
|
118
|
+
includeParamOnCompletion: true,
|
|
119
|
+
},
|
|
120
|
+
concurrencyLimit: this.importConcurrency,
|
|
121
|
+
}).then(() => {
|
|
122
|
+
utils_1.fsUtil.writeFile(this.modifiedCTsPath, this.modifiedCTs);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* @method serializeUpdateCTs
|
|
127
|
+
* @param {ApiOptions} apiOptions ApiOptions
|
|
128
|
+
* @returns {ApiOptions} ApiOptions
|
|
129
|
+
*/
|
|
130
|
+
serializeUpdateCTs(apiOptions) {
|
|
131
|
+
const { apiData: contentType } = apiOptions;
|
|
132
|
+
if (contentType.field_rules) {
|
|
133
|
+
delete contentType.field_rules;
|
|
134
|
+
}
|
|
135
|
+
const flag = {
|
|
136
|
+
suppressed: false,
|
|
137
|
+
references: false,
|
|
138
|
+
jsonRte: false,
|
|
139
|
+
jsonRteEmbeddedEntries: false,
|
|
140
|
+
};
|
|
141
|
+
(0, utils_1.suppressSchemaReference)(contentType.schema, flag);
|
|
142
|
+
// Check if suppress modified flag
|
|
143
|
+
if (flag.suppressed) {
|
|
144
|
+
this.modifiedCTs.push((0, lodash_1.find)(this.cTs, { uid: contentType.uid }));
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
// Note: Skips the content type from update if no reference found
|
|
148
|
+
apiOptions.additionalInfo = { skip: true };
|
|
149
|
+
return apiOptions;
|
|
150
|
+
}
|
|
151
|
+
if (flag.references) {
|
|
152
|
+
this.refCTs.push(contentType.uid);
|
|
153
|
+
}
|
|
154
|
+
if (flag.jsonRte) {
|
|
155
|
+
this.jsonRteCTs.push(contentType.uid);
|
|
156
|
+
if (flag.jsonRteEmbeddedEntries) {
|
|
157
|
+
this.jsonRteCTsWithRef.push(contentType.uid);
|
|
158
|
+
if (this.refCTs.indexOf(contentType.uid) === -1) {
|
|
159
|
+
this.refCTs.push(contentType.uid);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
(0, utils_1.lookupExtension)(this.importConfig, contentType.schema, this.importConfig.preserveStackVersion, this.installedExtensions);
|
|
164
|
+
const contentTypePayload = this.stack.contentType(contentType.uid);
|
|
165
|
+
Object.assign(contentTypePayload, (0, lodash_1.cloneDeep)(contentType));
|
|
166
|
+
apiOptions.apiData = contentTypePayload;
|
|
167
|
+
return apiOptions;
|
|
168
|
+
}
|
|
169
|
+
populateEntryCreatePayload() {
|
|
170
|
+
const requestOptions = [];
|
|
171
|
+
for (let locale of this.locales) {
|
|
172
|
+
for (let contentType of this.cTs) {
|
|
173
|
+
requestOptions.push({
|
|
174
|
+
cTUid: contentType.uid,
|
|
175
|
+
locale: locale.code,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return requestOptions;
|
|
180
|
+
}
|
|
181
|
+
async createEntries({ cTUid, locale }) {
|
|
182
|
+
var _a, _b;
|
|
183
|
+
const processName = 'Create Entries';
|
|
184
|
+
const indexFileName = 'index.json';
|
|
185
|
+
const basePath = path.join(this.entriesPath, cTUid, locale);
|
|
186
|
+
const fs = new cli_utilities_1.FsUtility({ basePath, indexFileName });
|
|
187
|
+
const indexer = fs.indexFileContent;
|
|
188
|
+
const indexerCount = (0, lodash_1.values)(indexer).length;
|
|
189
|
+
if (indexerCount === 0) {
|
|
190
|
+
return Promise.resolve();
|
|
191
|
+
}
|
|
192
|
+
(0, utils_1.log)(this.importConfig, `Starting to create entries for ${cTUid} in locale ${locale}`, 'info');
|
|
193
|
+
const isMasterLocale = locale === ((_b = (_a = this.importConfig) === null || _a === void 0 ? void 0 : _a.master_locale) === null || _b === void 0 ? void 0 : _b.code);
|
|
194
|
+
// Write created entries
|
|
195
|
+
const entriesCreateFileHelper = new cli_utilities_1.FsUtility({
|
|
196
|
+
moduleName: 'created-entries',
|
|
197
|
+
indexFileName: 'index.json',
|
|
198
|
+
basePath: path.join(this.entriesMapperPath, cTUid, locale),
|
|
199
|
+
chunkFileSize: this.entriesConfig.chunkFileSize,
|
|
200
|
+
keepMetadata: false,
|
|
201
|
+
omitKeys: this.entriesConfig.invalidKeys,
|
|
202
|
+
});
|
|
203
|
+
const contentType = (0, lodash_1.find)(this.cTs, { uid: cTUid });
|
|
204
|
+
const onSuccess = ({ response, apiData: entry, additionalInfo: { entryFileName } }) => {
|
|
205
|
+
(0, utils_1.log)(this.importConfig, `Created entry: '${entry.title}' of content type ${cTUid} in locale ${locale}`, 'info');
|
|
206
|
+
this.entriesUidMapper[entry.uid] = response.uid;
|
|
207
|
+
entry.sourceEntryFilePath = path.join(basePath, entryFileName); // stores source file path temporarily
|
|
208
|
+
entry.entryOldUid = entry.uid; // stores old uid temporarily
|
|
209
|
+
if (!isMasterLocale) {
|
|
210
|
+
this.autoCreatedEntries.push({ cTUid, locale, entryUid: response.uid });
|
|
211
|
+
}
|
|
212
|
+
entriesCreateFileHelper.writeIntoFile({ [response.uid]: entry }, { mapKeyVal: true });
|
|
213
|
+
};
|
|
214
|
+
const onReject = ({ error, apiData: { uid, title } }) => {
|
|
215
|
+
(0, utils_1.log)(this.importConfig, `${title} entry of content type ${cTUid} in locale ${locale} failed to create`, 'error');
|
|
216
|
+
(0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
|
|
217
|
+
this.failedEntries.push({ content_type: cTUid, locale, entry: { uid, title } });
|
|
218
|
+
};
|
|
219
|
+
for (const index in indexer) {
|
|
220
|
+
const chunk = await fs.readChunkFiles.next().catch((error) => {
|
|
221
|
+
(0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
|
|
222
|
+
});
|
|
223
|
+
if (chunk) {
|
|
224
|
+
let apiContent = (0, lodash_1.values)(chunk);
|
|
225
|
+
await this.makeConcurrentCall({
|
|
226
|
+
apiContent,
|
|
227
|
+
processName,
|
|
228
|
+
indexerCount,
|
|
229
|
+
currentIndexer: +index,
|
|
230
|
+
apiParams: {
|
|
231
|
+
reject: onReject,
|
|
232
|
+
resolve: onSuccess,
|
|
233
|
+
entity: 'create-entries',
|
|
234
|
+
includeParamOnCompletion: true,
|
|
235
|
+
serializeData: this.serializeEntries.bind(this),
|
|
236
|
+
additionalInfo: { contentType, locale, cTUid, entryFileName: indexer[index] },
|
|
237
|
+
},
|
|
238
|
+
concurrencyLimit: this.importConcurrency,
|
|
239
|
+
}).then(() => {
|
|
240
|
+
entriesCreateFileHelper === null || entriesCreateFileHelper === void 0 ? void 0 : entriesCreateFileHelper.completeFile(true);
|
|
241
|
+
(0, utils_1.log)(this.importConfig, `Created entries for content type ${cTUid} in locale ${locale}`, 'success');
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* @method serializeEntries
|
|
248
|
+
* @param {ApiOptions} apiOptions ApiOptions
|
|
249
|
+
* @returns {ApiOptions} ApiOptions
|
|
250
|
+
*/
|
|
251
|
+
serializeEntries(apiOptions) {
|
|
252
|
+
let { apiData: entry, additionalInfo: { cTUid, locale, contentType }, } = apiOptions;
|
|
253
|
+
if (this.jsonRteCTs.indexOf(cTUid) > -1) {
|
|
254
|
+
entry = (0, utils_1.removeUidsFromJsonRteFields)(entry, contentType.schema);
|
|
255
|
+
}
|
|
256
|
+
// remove entry references from json-rte fields
|
|
257
|
+
if (this.jsonRteCTsWithRef.indexOf(cTUid) > -1) {
|
|
258
|
+
entry = (0, utils_1.removeEntryRefsFromJSONRTE)(entry, contentType.schema);
|
|
259
|
+
}
|
|
260
|
+
// will replace all old asset uid/urls with new ones
|
|
261
|
+
entry = (0, utils_1.lookupAssets)({
|
|
262
|
+
content_type: contentType,
|
|
263
|
+
entry: entry,
|
|
264
|
+
}, this.assetUidMapper, this.assetUrlMapper, path.join(this.entriesPath, cTUid), this.installedExtensions);
|
|
265
|
+
delete entry.publish_details;
|
|
266
|
+
apiOptions.apiData = entry;
|
|
267
|
+
return apiOptions;
|
|
268
|
+
}
|
|
269
|
+
populateEntryUpdatePayload() {
|
|
270
|
+
const requestOptions = [];
|
|
271
|
+
for (let locale of this.locales) {
|
|
272
|
+
for (let cTUid of this.refCTs) {
|
|
273
|
+
requestOptions.push({
|
|
274
|
+
cTUid,
|
|
275
|
+
locale: locale.code,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return requestOptions;
|
|
280
|
+
}
|
|
281
|
+
async updateEntriesWithReferences({ cTUid, locale }) {
|
|
282
|
+
const processName = 'Update Entries';
|
|
283
|
+
const indexFileName = 'index.json';
|
|
284
|
+
const basePath = path.join(this.entriesMapperPath, cTUid, locale);
|
|
285
|
+
const fs = new cli_utilities_1.FsUtility({ basePath, indexFileName });
|
|
286
|
+
const indexer = fs.indexFileContent;
|
|
287
|
+
const indexerCount = (0, lodash_1.values)(indexer).length;
|
|
288
|
+
if (indexerCount === 0) {
|
|
289
|
+
return Promise.resolve();
|
|
290
|
+
}
|
|
291
|
+
(0, utils_1.log)(this.importConfig, `Starting to update entries with references for ${cTUid} in locale ${locale}`, 'info');
|
|
292
|
+
const contentType = (0, lodash_1.find)(this.cTs, { uid: cTUid });
|
|
293
|
+
const onSuccess = ({ response, apiData: { uid, url, title } }) => {
|
|
294
|
+
(0, utils_1.log)(this.importConfig, `Updated entry: '${title}' of content type ${cTUid} in locale ${locale}`, 'info');
|
|
295
|
+
};
|
|
296
|
+
const onReject = ({ error, apiData: { uid, title } }) => {
|
|
297
|
+
(0, utils_1.log)(this.importConfig, `${title} entry of content type ${cTUid} in locale ${locale} failed to update`, 'error');
|
|
298
|
+
(0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
|
|
299
|
+
this.failedEntries.push({ content_type: cTUid, locale, entry: { uid: this.entriesUidMapper[uid], title } });
|
|
300
|
+
};
|
|
301
|
+
for (const index in indexer) {
|
|
302
|
+
const chunk = await fs.readChunkFiles.next().catch((error) => {
|
|
303
|
+
(0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
|
|
304
|
+
});
|
|
305
|
+
if (chunk) {
|
|
306
|
+
let apiContent = (0, lodash_1.values)(chunk);
|
|
307
|
+
await this.makeConcurrentCall({
|
|
308
|
+
apiContent,
|
|
309
|
+
processName,
|
|
310
|
+
indexerCount,
|
|
311
|
+
currentIndexer: +index,
|
|
312
|
+
apiParams: {
|
|
313
|
+
reject: onReject,
|
|
314
|
+
resolve: onSuccess,
|
|
315
|
+
entity: 'update-entries',
|
|
316
|
+
includeParamOnCompletion: true,
|
|
317
|
+
serializeData: this.serializeUpdateEntries.bind(this),
|
|
318
|
+
additionalInfo: { contentType, locale, cTUid },
|
|
319
|
+
},
|
|
320
|
+
concurrencyLimit: this.importConcurrency,
|
|
321
|
+
}).then(() => {
|
|
322
|
+
(0, utils_1.log)(this.importConfig, `Updated entries for content type ${cTUid} in locale ${locale}`, 'success');
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* @method serializeUpdateEntries
|
|
329
|
+
* @param {ApiOptions} apiOptions ApiOptions
|
|
330
|
+
* @returns {ApiOptions} ApiOptions
|
|
331
|
+
*/
|
|
332
|
+
serializeUpdateEntries(apiOptions) {
|
|
333
|
+
let { apiData: entry, additionalInfo: { cTUid, locale, contentType }, } = apiOptions;
|
|
334
|
+
const sourceEntryFilePath = entry.sourceEntryFilePath;
|
|
335
|
+
const sourceEntry = (utils_1.fsUtil.readFile(sourceEntryFilePath) || {})[entry.entryOldUid];
|
|
336
|
+
// Removing temp values
|
|
337
|
+
delete entry.sourceEntryFilePath;
|
|
338
|
+
delete entry.entryOldUid;
|
|
339
|
+
if (this.jsonRteCTs.indexOf(cTUid) > -1) {
|
|
340
|
+
// the entries stored in eSuccessFilePath, have the same uids as the entries from source data
|
|
341
|
+
entry = (0, utils_1.restoreJsonRteEntryRefs)(entry, sourceEntry, contentType.schema, {
|
|
342
|
+
mappedAssetUids: this.assetUidMapper,
|
|
343
|
+
mappedAssetUrls: this.assetUrlMapper,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
entry = (0, utils_1.lookupEntries)({
|
|
347
|
+
content_type: contentType,
|
|
348
|
+
entry,
|
|
349
|
+
}, this.entriesUidMapper, path.join(this.entriesMapperPath, cTUid, locale));
|
|
350
|
+
const entryResponse = this.stack.contentType(contentType.uid).entry(this.entriesUidMapper[entry.uid]);
|
|
351
|
+
Object.assign(entryResponse, (0, lodash_1.cloneDeep)(entry));
|
|
352
|
+
delete entryResponse.publish_details;
|
|
353
|
+
apiOptions.apiData = entryResponse;
|
|
354
|
+
return apiOptions;
|
|
355
|
+
}
|
|
356
|
+
async enableMandatoryCTReferences() {
|
|
357
|
+
const onSuccess = ({ response: contentType, apiData: { uid } }) => {
|
|
358
|
+
(0, utils_1.log)(this.importConfig, `${uid} content type references updated`, 'success');
|
|
359
|
+
};
|
|
360
|
+
const onReject = ({ error, apiData: { uid } }) => {
|
|
361
|
+
(0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
|
|
362
|
+
throw new Error(`Failed to update references of content type ${uid}`);
|
|
363
|
+
};
|
|
364
|
+
return await this.makeConcurrentCall({
|
|
365
|
+
processName: 'Update content type references',
|
|
366
|
+
apiContent: this.modifiedCTs,
|
|
367
|
+
apiParams: {
|
|
368
|
+
serializeData: this.serializeUpdateCTsWithRef.bind(this),
|
|
369
|
+
reject: onReject.bind(this),
|
|
370
|
+
resolve: onSuccess.bind(this),
|
|
371
|
+
entity: 'update-cts',
|
|
372
|
+
includeParamOnCompletion: true,
|
|
373
|
+
},
|
|
374
|
+
concurrencyLimit: this.importConcurrency,
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* @method serializeUpdateCTsWithRef
|
|
379
|
+
* @param {ApiOptions} apiOptions ApiOptions
|
|
380
|
+
* @returns {ApiOptions} ApiOptions
|
|
381
|
+
*/
|
|
382
|
+
serializeUpdateCTsWithRef(apiOptions) {
|
|
383
|
+
const { apiData: contentType } = apiOptions;
|
|
384
|
+
if (contentType.field_rules) {
|
|
385
|
+
delete contentType.field_rules;
|
|
386
|
+
}
|
|
387
|
+
(0, utils_1.lookupExtension)(this.importConfig, contentType.schema, this.importConfig.preserveStackVersion, this.installedExtensions);
|
|
388
|
+
const contentTypePayload = this.stack.contentType(contentType.uid);
|
|
389
|
+
Object.assign(contentTypePayload, (0, lodash_1.cloneDeep)(contentType));
|
|
390
|
+
apiOptions.apiData = contentTypePayload;
|
|
391
|
+
return apiOptions;
|
|
392
|
+
}
|
|
393
|
+
async removeAutoCreatedEntries() {
|
|
394
|
+
const onSuccess = ({ response, apiData: { entryUid } }) => {
|
|
395
|
+
(0, utils_1.log)(this.importConfig, `Auto created entry in master locale removed - entry uid ${entryUid} `, 'success');
|
|
396
|
+
};
|
|
397
|
+
const onReject = ({ error, apiData: { entryUid } }) => {
|
|
398
|
+
(0, utils_1.log)(this.importConfig, `Failed to remove auto created entry in master locale - entry uid ${entryUid} \n ${(0, utils_1.formatError)(error)}`, 'error');
|
|
399
|
+
};
|
|
400
|
+
return await this.makeConcurrentCall({
|
|
401
|
+
processName: 'Remove auto created entry in master locale',
|
|
402
|
+
apiContent: this.autoCreatedEntries,
|
|
403
|
+
apiParams: {
|
|
404
|
+
reject: onReject.bind(this),
|
|
405
|
+
resolve: onSuccess.bind(this),
|
|
406
|
+
entity: 'delete-entries',
|
|
407
|
+
includeParamOnCompletion: true,
|
|
408
|
+
},
|
|
409
|
+
concurrencyLimit: this.importConcurrency,
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
async updateFieldRules() {
|
|
413
|
+
let cTsWithFieldRules = utils_1.fsUtil.readFile(path.join(this.cTsPath + '/field_rules_uid.json'));
|
|
414
|
+
if (!cTsWithFieldRules || (cTsWithFieldRules === null || cTsWithFieldRules === void 0 ? void 0 : cTsWithFieldRules.length) === 0) {
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
for (let cTUid of cTsWithFieldRules) {
|
|
418
|
+
const contentType = (0, lodash_1.find)(this.cTs, { uid: cTUid });
|
|
419
|
+
if (contentType.field_rules) {
|
|
420
|
+
let fieldRuleLength = contentType.field_rules.length;
|
|
421
|
+
for (let k = 0; k < fieldRuleLength; k++) {
|
|
422
|
+
let fieldRuleConditionLength = contentType.field_rules[k].conditions.length;
|
|
423
|
+
for (let i = 0; i < fieldRuleConditionLength; i++) {
|
|
424
|
+
if (contentType.field_rules[k].conditions[i].operand_field === 'reference') {
|
|
425
|
+
let fieldRulesValue = contentType.field_rules[k].conditions[i].value;
|
|
426
|
+
let fieldRulesArray = fieldRulesValue.split('.');
|
|
427
|
+
let updatedValue = [];
|
|
428
|
+
for (const element of fieldRulesArray) {
|
|
429
|
+
let splittedFieldRulesValue = element;
|
|
430
|
+
if (this.entriesUidMapper.hasOwnProperty(splittedFieldRulesValue)) {
|
|
431
|
+
updatedValue.push(this.entriesUidMapper[splittedFieldRulesValue]);
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
updatedValue.push(element);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
contentType.field_rules[k].conditions[i].value = updatedValue.join('.');
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
const contentTypeResponse = await this.stack
|
|
442
|
+
.contentType(contentType.uid)
|
|
443
|
+
.fetch()
|
|
444
|
+
.catch((error) => {
|
|
445
|
+
(0, utils_1.log)(this.importConfig, `failed to update the field rules of ${cTUid} ${(0, utils_1.formatError)(error)}`, 'error');
|
|
446
|
+
});
|
|
447
|
+
if (!contentTypeResponse) {
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
contentTypeResponse.field_rules = contentType.field_rules;
|
|
451
|
+
await contentTypeResponse.update().catch((error) => {
|
|
452
|
+
(0, utils_1.log)(this.importConfig, `failed to update the field rules of ${cTUid} ${(0, utils_1.formatError)(error)}`, 'error');
|
|
453
|
+
});
|
|
454
|
+
(0, utils_1.log)(this.importConfig, `Updated the field rules of ${cTUid}`, 'info');
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
(0, utils_1.log)(this.importConfig, `No field rules found in content type ${cTUid} to update`, 'error');
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
async publishEntries({ cTUid, locale }) {
|
|
462
|
+
const processName = 'Publish Entries';
|
|
463
|
+
const indexFileName = 'index.json';
|
|
464
|
+
const basePath = path.join(this.entriesPath, cTUid, locale);
|
|
465
|
+
const fs = new cli_utilities_1.FsUtility({ basePath, indexFileName });
|
|
466
|
+
const indexer = fs.indexFileContent;
|
|
467
|
+
const indexerCount = (0, lodash_1.values)(indexer).length;
|
|
468
|
+
const contentType = (0, lodash_1.find)(this.cTs, { uid: cTUid });
|
|
469
|
+
if (indexerCount === 0) {
|
|
470
|
+
return Promise.resolve();
|
|
471
|
+
}
|
|
472
|
+
(0, utils_1.log)(this.importConfig, `Starting publish entries for ${cTUid} in locale ${locale}`, 'info');
|
|
473
|
+
const onSuccess = ({ response, apiData: { environments }, additionalInfo: { entryUid } }) => {
|
|
474
|
+
(0, utils_1.log)(this.importConfig, `Published entry: '${entryUid}' of content type ${cTUid} and locale ${locale} in ${environments === null || environments === void 0 ? void 0 : environments.join(',')} environments`, 'info');
|
|
475
|
+
};
|
|
476
|
+
const onReject = ({ error, apiData, additionalInfo: { entryUid } }) => {
|
|
477
|
+
(0, utils_1.log)(this.importConfig, `${entryUid} entry of content type ${cTUid} in locale ${locale} failed to publish`, 'error');
|
|
478
|
+
(0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
|
|
479
|
+
};
|
|
480
|
+
for (const index in indexer) {
|
|
481
|
+
const chunk = await fs.readChunkFiles.next().catch((error) => {
|
|
482
|
+
(0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
|
|
483
|
+
});
|
|
484
|
+
if (chunk) {
|
|
485
|
+
let apiContent = (0, lodash_1.values)(chunk);
|
|
486
|
+
await this.makeConcurrentCall({
|
|
487
|
+
apiContent,
|
|
488
|
+
processName,
|
|
489
|
+
indexerCount,
|
|
490
|
+
currentIndexer: +index,
|
|
491
|
+
apiParams: {
|
|
492
|
+
reject: onReject,
|
|
493
|
+
resolve: onSuccess,
|
|
494
|
+
entity: 'publish-entries',
|
|
495
|
+
includeParamOnCompletion: true,
|
|
496
|
+
serializeData: this.serializePublishEntries.bind(this),
|
|
497
|
+
additionalInfo: { contentType, locale, cTUid },
|
|
498
|
+
},
|
|
499
|
+
concurrencyLimit: this.importConcurrency,
|
|
500
|
+
}).then(() => {
|
|
501
|
+
(0, utils_1.log)(this.importConfig, `Published entries for content type ${cTUid} in locale ${locale}`, 'success');
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* @method serializeEntries
|
|
508
|
+
* @param {ApiOptions} apiOptions ApiOptions
|
|
509
|
+
* @returns {ApiOptions} ApiOptions
|
|
510
|
+
*/
|
|
511
|
+
serializePublishEntries(apiOptions) {
|
|
512
|
+
let { apiData: entry, additionalInfo } = apiOptions;
|
|
513
|
+
additionalInfo.entryUid = this.entriesUidMapper[entry.uid];
|
|
514
|
+
const requestObject = {
|
|
515
|
+
environments: [],
|
|
516
|
+
locales: [],
|
|
517
|
+
};
|
|
518
|
+
if (entry.publish_details && entry.publish_details.length > 0) {
|
|
519
|
+
(0, lodash_1.forEach)(entry.publish_details, (pubObject) => {
|
|
520
|
+
if (this.envs.hasOwnProperty(pubObject.environment) &&
|
|
521
|
+
(0, lodash_1.indexOf)(requestObject.environments, this.envs[pubObject.environment].name) === -1) {
|
|
522
|
+
requestObject.environments.push(this.envs[pubObject.environment].name);
|
|
523
|
+
}
|
|
524
|
+
if (pubObject.locale && (0, lodash_1.indexOf)(requestObject.locales, pubObject.locale) === -1) {
|
|
525
|
+
requestObject.locales.push(pubObject.locale);
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
else {
|
|
530
|
+
additionalInfo.skip = true;
|
|
531
|
+
}
|
|
532
|
+
apiOptions.apiData = requestObject;
|
|
533
|
+
return apiOptions;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
exports.default = EntriesImport;
|
|
@@ -12,7 +12,7 @@ export default class ImportMarketplaceApps extends BaseClass {
|
|
|
12
12
|
private appUidMapping;
|
|
13
13
|
private installationUidMapping;
|
|
14
14
|
private installedApps;
|
|
15
|
-
private
|
|
15
|
+
private appOriginalName;
|
|
16
16
|
developerHubBaseUrl: string;
|
|
17
17
|
sdkClient: ContentstackClient;
|
|
18
18
|
nodeCrypto: NodeCrypto;
|
|
@@ -40,7 +40,10 @@ export default class ImportMarketplaceApps extends BaseClass {
|
|
|
40
40
|
appCreationCallback(app: any, response: any, appSuffix: number): Promise<any>;
|
|
41
41
|
/**
|
|
42
42
|
* @method installApps
|
|
43
|
-
*
|
|
43
|
+
*
|
|
44
|
+
* @param {Record<string, any>} app
|
|
45
|
+
* @param {Record<string, any>[]} installedApps
|
|
46
|
+
* @returns {Promise<void>}
|
|
44
47
|
*/
|
|
45
48
|
installApps(app: any): Promise<void>;
|
|
46
49
|
/**
|