@contentstack/cli-cm-import 1.28.0 → 2.0.0-beta

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.
Files changed (87) hide show
  1. package/README.md +5 -7
  2. package/lib/commands/cm/stacks/import.d.ts +2 -0
  3. package/lib/commands/cm/stacks/import.js +46 -11
  4. package/lib/config/index.js +0 -1
  5. package/lib/import/module-importer.d.ts +2 -2
  6. package/lib/import/module-importer.js +9 -25
  7. package/lib/import/modules/assets.d.ts +6 -0
  8. package/lib/import/modules/assets.js +102 -25
  9. package/lib/import/modules/base-class.d.ts +17 -0
  10. package/lib/import/modules/base-class.js +45 -0
  11. package/lib/import/modules/content-types.d.ts +7 -10
  12. package/lib/import/modules/content-types.js +132 -68
  13. package/lib/import/modules/custom-roles.d.ts +6 -2
  14. package/lib/import/modules/custom-roles.js +80 -69
  15. package/lib/import/modules/entries.d.ts +7 -0
  16. package/lib/import/modules/entries.js +278 -163
  17. package/lib/import/modules/environments.d.ts +3 -0
  18. package/lib/import/modules/environments.js +69 -38
  19. package/lib/import/modules/extensions.d.ts +3 -0
  20. package/lib/import/modules/extensions.js +99 -64
  21. package/lib/import/modules/global-fields.d.ts +8 -1
  22. package/lib/import/modules/global-fields.js +123 -63
  23. package/lib/import/modules/index.d.ts +1 -0
  24. package/lib/import/modules/index.js +1 -0
  25. package/lib/import/modules/labels.d.ts +3 -0
  26. package/lib/import/modules/labels.js +104 -54
  27. package/lib/import/modules/locales.d.ts +15 -4
  28. package/lib/import/modules/locales.js +194 -94
  29. package/lib/import/modules/marketplace-apps.d.ts +6 -3
  30. package/lib/import/modules/marketplace-apps.js +177 -102
  31. package/lib/import/modules/personalize.d.ts +11 -4
  32. package/lib/import/modules/personalize.js +138 -47
  33. package/lib/import/modules/stack.d.ts +6 -0
  34. package/lib/import/modules/stack.js +71 -27
  35. package/lib/import/modules/taxonomies.d.ts +4 -2
  36. package/lib/import/modules/taxonomies.js +60 -46
  37. package/lib/import/modules/variant-entries.d.ts +7 -4
  38. package/lib/import/modules/variant-entries.js +76 -35
  39. package/lib/import/modules/webhooks.d.ts +3 -0
  40. package/lib/import/modules/webhooks.js +71 -40
  41. package/lib/import/modules/workflows.d.ts +3 -0
  42. package/lib/import/modules/workflows.js +98 -48
  43. package/lib/types/default-config.d.ts +0 -1
  44. package/lib/types/import-config.d.ts +0 -1
  45. package/lib/types/index.d.ts +1 -12
  46. package/lib/utils/backup-handler.js +1 -2
  47. package/lib/utils/constants.d.ts +243 -0
  48. package/lib/utils/constants.js +264 -0
  49. package/lib/utils/import-config-handler.js +2 -7
  50. package/lib/utils/import-path-resolver.d.ts +1 -1
  51. package/lib/utils/import-path-resolver.js +5 -5
  52. package/lib/utils/index.d.ts +1 -1
  53. package/lib/utils/index.js +6 -2
  54. package/lib/utils/marketplace-app-helper.js +3 -8
  55. package/lib/utils/progress-strategy-registry.d.ts +7 -0
  56. package/lib/utils/progress-strategy-registry.js +72 -0
  57. package/lib/utils/setup-branch.js +1 -1
  58. package/oclif.manifest.json +2 -2
  59. package/package.json +2 -2
  60. package/lib/import/modules-js/assets.d.ts +0 -33
  61. package/lib/import/modules-js/assets.js +0 -428
  62. package/lib/import/modules-js/content-types.d.ts +0 -34
  63. package/lib/import/modules-js/content-types.js +0 -204
  64. package/lib/import/modules-js/custom-roles.d.ts +0 -15
  65. package/lib/import/modules-js/custom-roles.js +0 -143
  66. package/lib/import/modules-js/entries.d.ts +0 -54
  67. package/lib/import/modules-js/entries.js +0 -1280
  68. package/lib/import/modules-js/environments.d.ts +0 -13
  69. package/lib/import/modules-js/environments.js +0 -85
  70. package/lib/import/modules-js/extensions.d.ts +0 -18
  71. package/lib/import/modules-js/extensions.js +0 -86
  72. package/lib/import/modules-js/global-fields.d.ts +0 -13
  73. package/lib/import/modules-js/global-fields.js +0 -106
  74. package/lib/import/modules-js/index.d.ts +0 -1
  75. package/lib/import/modules-js/index.js +0 -33
  76. package/lib/import/modules-js/labels.d.ts +0 -20
  77. package/lib/import/modules-js/labels.js +0 -148
  78. package/lib/import/modules-js/locales.d.ts +0 -24
  79. package/lib/import/modules-js/locales.js +0 -196
  80. package/lib/import/modules-js/marketplace-apps.d.ts +0 -63
  81. package/lib/import/modules-js/marketplace-apps.js +0 -429
  82. package/lib/import/modules-js/webhooks.d.ts +0 -17
  83. package/lib/import/modules-js/webhooks.js +0 -85
  84. package/lib/import/modules-js/workflows.d.ts +0 -19
  85. package/lib/import/modules-js/workflows.js +0 -170
  86. package/lib/utils/log.d.ts +0 -12
  87. package/lib/utils/log.js +0 -31
@@ -1,1280 +0,0 @@
1
- /*!
2
- * Contentstack Import
3
- * Copyright (c) 2024 Contentstack LLC
4
- * MIT Licensed
5
- */
6
- const Promise = require('bluebird');
7
- const fs = require('fs');
8
- const path = require('path');
9
- const _ = require('lodash');
10
- const mkdirp = require('mkdirp');
11
- const chalk = require('chalk');
12
- const { fileHelper, log, formatError, lookupExtension, suppressSchemaReference, lookupAssets, lookupEntries, } = require('../../utils');
13
- const { default: config } = require('../../config');
14
- const { sanitizePath } = require('@contentstack/cli-utilities');
15
- const addlogs = log;
16
- module.exports = class ImportEntries {
17
- constructor(importConfig, stackAPIClient) {
18
- this.skipFiles = ['__master.json', '__priority.json', 'schema.json', '.DS_Store'];
19
- this.config = _.merge(config, importConfig);
20
- this.stackAPIClient = stackAPIClient;
21
- this.mappedAssetUidPath = path.resolve(this.config.data, 'mapper', 'assets', 'uid-mapping.json');
22
- this.mappedAssetUrlPath = path.resolve(this.config.data, 'mapper', 'assets', 'url-mapping.json');
23
- this.entryMapperPath = path.resolve(this.config.data, 'mapper', 'entries');
24
- this.environmentPath = path.resolve(this.config.data, 'environments', 'environments.json');
25
- mkdirp.sync(this.entryMapperPath);
26
- this.entryUidMapperPath = path.join(this.entryMapperPath, 'uid-mapping.json');
27
- this.uniqueUidMapperPath = path.join(this.entryMapperPath, 'unique-mapping.json');
28
- this.modifiedSchemaPath = path.join(this.entryMapperPath, 'modified-schemas.json');
29
- this.createdEntriesWOUidPath = path.join(this.entryMapperPath, 'created-entries-wo-uid.json');
30
- this.failedWOPath = path.join(this.entryMapperPath, 'failedWO.json');
31
- this.reqConcurrency = this.config.concurrency;
32
- this.eConfig = this.config.modules.entries;
33
- this.ePath = path.resolve(this.config.data, this.eConfig.dirName);
34
- this.ctPath = path.resolve(this.config.data, this.config.modules.content_types.dirName);
35
- this.lPath = path.resolve(this.config.data, this.config.modules.locales.dirName, this.config.modules.locales.fileName);
36
- this.importConcurrency = this.eConfig.importConcurrency || this.config.importConcurrency;
37
- // Object of Schemas, referred to by their content type uid
38
- this.ctSchemas = {};
39
- // Array of content type uids, that have reference fields
40
- this.refSchemas = [];
41
- // map of content types uids and their json-rte fields
42
- this.ctJsonRte = [];
43
- // map of content types uids and their json-rte fields
44
- this.ctJsonRteWithEntryRefs = [];
45
- // Entry refs that are held back to resolve after all entries have been created
46
- this.jsonRteEntryRefs = {};
47
- // Collection of entries, that were not created, as they already exist on Stack
48
- this.createdEntriesWOUid = [];
49
- // Collection of entry uids, mapped to the language they exist in
50
- this.uniqueUids = {};
51
- // Map of old entry uid to new
52
- this.mappedUids = {};
53
- // Entries that were created successfully
54
- this.success = [];
55
- // Entries that failed to get created OR updated
56
- this.fails = [];
57
- // List of installed extensions to replace uid
58
- this.installedExtensions = [];
59
- let files = fs.readdirSync(this.ctPath);
60
- this.environment = fileHelper.readFileSync(this.environmentPath);
61
- for (let index in files) {
62
- if (index) {
63
- try {
64
- if (this.skipFiles.indexOf(files[index]) === -1) {
65
- if (files[index] != 'field_rules_uid.json') {
66
- let schema = require(path.resolve(path.join(this.ctPath, files[index])));
67
- this.ctSchemas[schema.uid] = schema;
68
- }
69
- }
70
- }
71
- catch (error) {
72
- addlogs(this.config, `Failed to read the content types to import entries ${formatError(error)}`, 'error');
73
- process.exit(0);
74
- }
75
- }
76
- }
77
- }
78
- async start() {
79
- let self = this;
80
- this.masterLanguage = this.config.master_locale;
81
- log(this.config, 'Migrating entries', 'success');
82
- let languages = fileHelper.readFileSync(this.lPath);
83
- const appMapperPath = path.join(this.config.data, 'mapper', 'marketplace_apps', 'uid-mapping.json');
84
- this.installedExtensions = ((await fileHelper.readFileSync(appMapperPath)) || { extension_uid: {} }).extension_uid;
85
- return new Promise((resolve, reject) => {
86
- let langs = [self.masterLanguage.code];
87
- for (let i in languages) {
88
- if (i) {
89
- langs.push(languages[i].code);
90
- }
91
- }
92
- // Step 1: Removes field rules from content type
93
- // This allows to handle cases like self references and circular reference
94
- // if mandatory reference fields are not filed in entries then avoids the error
95
- // Also remove field visibility rules
96
- return self
97
- .supressFields()
98
- .then(async () => {
99
- log(this.config, 'Completed suppressing content type reference fields', 'success');
100
- let mappedAssetUids = fileHelper.readFileSync(this.mappedAssetUidPath) || {};
101
- let mappedAssetUrls = fileHelper.readFileSync(this.mappedAssetUrlPath) || {};
102
- // Step 2: Iterate over available languages to create entries in each.
103
- let counter = 0;
104
- return Promise.map(langs, async () => {
105
- let lang = langs[counter];
106
- if ((self.config.hasOwnProperty('onlylocales') && self.config.onlylocales.indexOf(lang) !== -1) ||
107
- !self.config.hasOwnProperty('onlylocales')) {
108
- addlogs(self.config, `Starting to create entries ${lang} locale`, 'info');
109
- await self.createEntries(lang, mappedAssetUids, mappedAssetUrls);
110
- log(this.config, 'Entries created successfully', 'info');
111
- try {
112
- await self.getCreatedEntriesWOUid();
113
- }
114
- catch (error) {
115
- addlogs(self.config, `Failed get the existing entries to update the mapper ${formatError(error)}, 'error`);
116
- }
117
- log(this.config, 'Starting to update entries with references', 'info');
118
- await self.repostEntries(lang);
119
- log(this.config, "Successfully imported '" + lang + "' entries!", 'success');
120
- counter++;
121
- }
122
- else {
123
- addlogs(self.config, `'${lang}' has not been configured for import, thus skipping it`, 'success');
124
- counter++;
125
- }
126
- }, {
127
- concurrency: 1,
128
- }).then(async () => {
129
- // Step 3: Revert all the changes done in content type in step 1
130
- log(this.config, 'Restoring content type changes', 'info');
131
- await self.unSuppressFields();
132
- log(this.config, 'Removing entries from master language which got created by default', 'info');
133
- await self.removeBuggedEntries();
134
- log(this.config, 'Updating the field rules of content type', 'info');
135
- let ct_field_visibility_uid = fileHelper.readFileSync(path.join(this.ctPath + '/field_rules_uid.json'));
136
- let ct_files = fs.readdirSync(this.ctPath);
137
- if (ct_field_visibility_uid && ct_field_visibility_uid != 'undefined') {
138
- for (const element of ct_field_visibility_uid) {
139
- if (ct_files.indexOf(element + '.json') > -1) {
140
- let schema = require(path.resolve(this.ctPath, element));
141
- try {
142
- await self.field_rules_update(schema);
143
- }
144
- catch (error) {
145
- addlogs(self.config, `Failed to update the field rules for content type '${schema.uid}' ${formatError(error)}`, 'error');
146
- }
147
- }
148
- }
149
- }
150
- log(this.config, chalk.green('Entries have been imported successfully!'), 'success');
151
- if (this.config.entriesPublish) {
152
- log(this.config, chalk.green('Publishing entries'), 'success');
153
- return self
154
- .publish(langs)
155
- .then(() => {
156
- log(this.config, chalk.green('All the entries have been published successfully'), 'success');
157
- return resolve();
158
- })
159
- .catch((error) => {
160
- log(this.config, `Error in publishing entries ${formatError(error)}`, 'error');
161
- });
162
- }
163
- return resolve();
164
- });
165
- })
166
- .catch((error) => {
167
- log(self.config, formatError(error), 'error');
168
- reject('Failed import entries');
169
- });
170
- });
171
- }
172
- createEntries(lang, mappedAssetUids, mappedAssetUrls) {
173
- let self = this;
174
- return new Promise(async (resolve, reject) => {
175
- let contentTypeUids = Object.keys(self.ctSchemas);
176
- if (fs.existsSync(this.entryUidMapperPath)) {
177
- self.mappedUids = await fileHelper.readLargeFile(this.entryUidMapperPath);
178
- }
179
- self.mappedUids = self.mappedUids || {};
180
- return Promise.map(contentTypeUids, async (ctUid) => {
181
- let eLangFolderPath = path.join(this.entryMapperPath, lang);
182
- let eLogFolderPath = path.join(this.entryMapperPath, lang, ctUid);
183
- mkdirp.sync(eLogFolderPath);
184
- // entry file path
185
- let eFilePath = path.resolve(this.ePath, ctUid, lang + '.json');
186
- // log created/updated entries
187
- let successEntryLogPath = path.join(eLogFolderPath, 'success.json');
188
- let failedEntryLogPath = path.join(eLogFolderPath, 'fails.json');
189
- let createdEntriesPath = path.join(eLogFolderPath, 'created-entries.json');
190
- let createdEntries = {};
191
- if (fs.existsSync(createdEntriesPath)) {
192
- createdEntries = await fileHelper.readLargeFile(createdEntriesPath);
193
- createdEntries = createdEntries || {};
194
- }
195
- if (fs.existsSync(eFilePath)) {
196
- let entries = await fileHelper.readLargeFile(eFilePath);
197
- if (!_.isPlainObject(entries) || _.isEmpty(entries)) {
198
- log(this.config, chalk.white("No entries were found for Content type:'" + ctUid + "' in '" + lang + "' language!"), 'success');
199
- }
200
- else {
201
- addlogs(this.config, `Creating entries for content type ${ctUid} in language ${lang} ...`, 'success');
202
- for (let eUid in entries) {
203
- if (eUid) {
204
- try {
205
- // check ctUid in self.ctJsonRte array, if ct exists there... only then remove entry references for json rte
206
- // also with json rte, api creates the json-rte field with the same uid as passed in the payload.
207
- if (self.ctJsonRte.indexOf(ctUid) > -1) {
208
- entries[eUid] = self.removeUidsFromJsonRteFields(entries[eUid], self.ctSchemas[ctUid].schema);
209
- }
210
- // remove entry references from json-rte fields
211
- if (self.ctJsonRteWithEntryRefs.indexOf(ctUid) > -1) {
212
- entries[eUid] = self.removeEntryRefsFromJSONRTE(entries[eUid], self.ctSchemas[ctUid].schema);
213
- }
214
- // will replace all old asset uid/urls with new ones
215
- entries[eUid] = lookupAssets({
216
- content_type: self.ctSchemas[ctUid],
217
- entry: entries[eUid],
218
- }, mappedAssetUids, mappedAssetUrls, eLangFolderPath, self.installedExtensions);
219
- }
220
- catch (error) {
221
- addlogs(this.config, 'Failed to update entry while creating entry id ' + eUid);
222
- addlogs(this.config, formatError(error), 'error');
223
- }
224
- }
225
- }
226
- let eUids = Object.keys(entries);
227
- let batches = [];
228
- let entryBatchLimit = this.eConfig.batchLimit || 10;
229
- let batchSize = Math.round(entryBatchLimit / 3);
230
- // Run entry creation in batches of ~16~ entries
231
- for (let i = 0; i < eUids.length; i += batchSize) {
232
- batches.push(eUids.slice(i, i + batchSize));
233
- }
234
- return Promise.map(batches, async (batch) => {
235
- return Promise.map(batch, async (eUid, batchIndex) => {
236
- // if entry is already created
237
- if (createdEntries.hasOwnProperty(eUid)) {
238
- log(this.config, 'Skipping ' +
239
- JSON.stringify({
240
- content_type: ctUid,
241
- locale: lang,
242
- oldEntryUid: eUid,
243
- newEntryUid: createdEntries[eUid],
244
- }) +
245
- ' as it is already created', 'success');
246
- self.success[ctUid] = createdEntries[eUid];
247
- // if its a non-master language, i.e. the entry isn't present in the master language
248
- if (lang !== this.masterLanguage.code) {
249
- self.uniqueUids[eUid] = self.uniqueUids[eUid] || {};
250
- if (self.uniqueUids[eUid].locales) {
251
- self.uniqueUids[eUid].locales.push(lang);
252
- }
253
- else {
254
- self.uniqueUids[eUid].locales = [lang];
255
- }
256
- self.uniqueUids[eUid].content_type = ctUid;
257
- }
258
- return;
259
- }
260
- let requestObject = {
261
- qs: {
262
- locale: lang,
263
- },
264
- json: {
265
- entry: entries[eUid],
266
- },
267
- };
268
- if (self.mappedUids.hasOwnProperty(eUid)) {
269
- let entryToUpdate = self.stackAPIClient.contentType(ctUid).entry(self.mappedUids[eUid]);
270
- Object.assign(entryToUpdate, _.cloneDeep(entries[eUid]));
271
- return entryToUpdate
272
- .update({ locale: entryToUpdate.locale })
273
- .then(async (entryResponse) => {
274
- self.success[ctUid] = self.success[ctUid] || [];
275
- self.success[ctUid].push(entries[eUid]);
276
- if (!self.mappedUids.hasOwnProperty(eUid)) {
277
- self.mappedUids[eUid] = entryResponse.uid;
278
- createdEntries = entryResponse;
279
- // if its a non-master language, i.e. the entry isn't present in the master language
280
- if (lang !== this.masterLanguage.code) {
281
- self.uniqueUids[eUid] = self.uniqueUids[eUid] || {};
282
- if (self.uniqueUids[eUid].locales) {
283
- self.uniqueUids[eUid].locales.push(lang);
284
- }
285
- else {
286
- self.uniqueUids[eUid].locales = [lang];
287
- }
288
- self.uniqueUids[eUid].content_type = ctUid;
289
- }
290
- }
291
- })
292
- .catch((error) => {
293
- log(this.config, `Failed to update an entry ${eUid} ${formatError(error)}`, 'error');
294
- self.fails.push({
295
- content_type: ctUid,
296
- locale: lang,
297
- entry: entries[eUid],
298
- error: formatError(error),
299
- });
300
- return error;
301
- });
302
- }
303
- delete requestObject.json.entry.publish_details;
304
- return self.stackAPIClient
305
- .contentType(ctUid)
306
- .entry()
307
- .create(requestObject.json, { locale: lang })
308
- .then(async (entryResponse) => {
309
- self.success[ctUid] = self.success[ctUid] || [];
310
- self.success[ctUid].push(entries[eUid]);
311
- if (!self.mappedUids.hasOwnProperty(eUid)) {
312
- self.mappedUids[eUid] = entryResponse.uid;
313
- createdEntries = entryResponse;
314
- // if its a non-master language, i.e. the entry isn't present in the master language
315
- if (lang !== this.masterLanguage.code) {
316
- self.uniqueUids[eUid] = self.uniqueUids[eUid] || {};
317
- if (self.uniqueUids[eUid].locales) {
318
- self.uniqueUids[eUid].locales.push(lang);
319
- }
320
- else {
321
- self.uniqueUids[eUid].locales = [lang];
322
- }
323
- self.uniqueUids[eUid].content_type = ctUid;
324
- }
325
- }
326
- })
327
- .catch((error) => {
328
- if (error.hasOwnProperty('errorCode') && error.errorCode === 119) {
329
- if (error.errors.title) {
330
- log(this.config, 'Entry ' + eUid + ' already exist, skip to avoid creating a duplicate entry', 'error');
331
- }
332
- else {
333
- log(this.config, `Failed to create an entry '${eUid}' ${formatError(error)} Title of the failed entry: '${entries[eUid].title}'`, 'error');
334
- }
335
- self.createdEntriesWOUid.push({
336
- content_type: ctUid,
337
- locale: lang,
338
- entry: entries[eUid],
339
- error: error,
340
- });
341
- fileHelper.writeFileSync(this.createdEntriesWOUidPath, self.createdEntriesWOUid);
342
- return;
343
- }
344
- // TODO: if status code: 422, check the reason
345
- // 429 for rate limit
346
- log(this.config, `Failed to create an entry '${eUid}' ${formatError(error)}. Title of the failed entry: '${entries[eUid].title}'`, 'error');
347
- self.fails.push({
348
- content_type: ctUid,
349
- locale: lang,
350
- entry: entries[eUid],
351
- error: error,
352
- });
353
- });
354
- // create/update 5 entries at a time
355
- }, {
356
- concurrency: this.importConcurrency,
357
- }).then(() => {
358
- fileHelper.writeFileSync(successEntryLogPath, self.success[ctUid]);
359
- fileHelper.writeFileSync(failedEntryLogPath, self.fails[ctUid]);
360
- fileHelper.writeFileSync(this.entryUidMapperPath, self.mappedUids);
361
- fileHelper.writeFileSync(this.uniqueUidMapperPath, self.uniqueUids);
362
- fileHelper.writeFileSync(createdEntriesPath, createdEntries);
363
- });
364
- // process one batch at a time
365
- }, {
366
- concurrency: 1,
367
- }).then(() => {
368
- if (self.success && self.success[ctUid] && self.success[ctUid].length > 0)
369
- log(this.config, self.success[ctUid].length +
370
- ' entries created successfully in ' +
371
- ctUid +
372
- ' content type in ' +
373
- lang +
374
- ' locale!', 'success');
375
- if (self.fails && self.fails[ctUid] && self.fails[ctUid].length > 0)
376
- log(this.config, self.fails[ctUid].length +
377
- ' entries failed to create in ' +
378
- ctUid +
379
- ' content type in ' +
380
- lang +
381
- ' locale!', 'error');
382
- self.success[ctUid] = [];
383
- self.fails[ctUid] = [];
384
- });
385
- }
386
- }
387
- else {
388
- log(this.config, `Unable to find entry file path for '${ctUid}' content type!\nThe file '${eFilePath}' does not exist!`, 'error');
389
- }
390
- }, {
391
- concurrency: 1,
392
- })
393
- .then(() => {
394
- log(this.config, chalk.green("Entries created successfully in '" + lang + "' language"), 'success');
395
- return resolve();
396
- })
397
- .catch((error) => {
398
- var _a, _b;
399
- let title = (_b = JSON.parse(((_a = error === null || error === void 0 ? void 0 : error.request) === null || _a === void 0 ? void 0 : _a.data) || '{}').entry) === null || _b === void 0 ? void 0 : _b.title;
400
- addlogs(this.config, chalk.red("Failed to create entries in '" +
401
- lang +
402
- "' language. " +
403
- 'Title of the failed entry: ' +
404
- `'${title || ''}'`), 'error');
405
- return reject(error);
406
- });
407
- });
408
- }
409
- getCreatedEntriesWOUid() {
410
- let self = this;
411
- return new Promise((resolve) => {
412
- self.createdEntriesWOUid = fileHelper.readFileSync(this.createdEntriesWOUidPath);
413
- self.failedWO = [];
414
- if (_.isArray(self.createdEntriesWOUid) && self.createdEntriesWOUid.length > 0) {
415
- return Promise.map(self.createdEntriesWOUid, (entry) => {
416
- return self.fetchEntry(entry);
417
- }, {
418
- concurrency: this.importConcurrency,
419
- }).then(() => {
420
- fileHelper.writeFileSync(this.failedWOPath, self.failedWO);
421
- log(this.config, 'Mapped entries without mapped uid successfully!', 'success');
422
- return resolve();
423
- });
424
- }
425
- log(this.config, 'No entries without mapped uid found!', 'success');
426
- return resolve();
427
- });
428
- }
429
- repostEntries(lang) {
430
- let self = this;
431
- return new Promise(async (resolve, reject) => {
432
- let _mapped_ = await fileHelper.readLargeFile(path.join(this.entryMapperPath, 'uid-mapping.json'));
433
- if (_.isPlainObject(_mapped_)) {
434
- self.mappedUids = _.merge(_mapped_, self.mappedUids);
435
- }
436
- return Promise.map(self.refSchemas, async (ctUid) => {
437
- let eFolderPath = path.join(this.entryMapperPath, lang, ctUid);
438
- let eSuccessFilePath = path.join(eFolderPath, 'success.json');
439
- let eFilePath = path.resolve(this.ePath, ctUid, lang + '.json');
440
- let sourceStackEntries = await fileHelper.readLargeFile(eFilePath);
441
- if (!fs.existsSync(eSuccessFilePath)) {
442
- log(this.config, 'Success file was not found at: ' + eSuccessFilePath, 'success');
443
- return;
444
- }
445
- let entries = await fileHelper.readLargeFile(eSuccessFilePath, { type: 'array' }); // TBD LARGE
446
- entries = entries || [];
447
- if (entries.length === 0) {
448
- log(this.config, "No entries were created to be updated in '" + lang + "' language!", 'success');
449
- return;
450
- }
451
- // Keep track of entries that have their references updated
452
- let refsUpdatedUids = fileHelper.readFileSync(path.join(eFolderPath, 'refsUpdatedUids.json'));
453
- let refsUpdateFailed = fileHelper.readFileSync(path.join(eFolderPath, 'refsUpdateFailed.json'));
454
- let schema = self.ctSchemas[ctUid];
455
- let batches = [];
456
- refsUpdatedUids = refsUpdatedUids || [];
457
- refsUpdateFailed = refsUpdateFailed || [];
458
- // map reference uids @mapper/language/mapped-uids.json
459
- // map failed reference uids @mapper/language/unmapped-uids.json
460
- let refUidMapperPath = path.join(this.entryMapperPath, lang);
461
- addlogs(this.config, 'staring to update the entry for reposting');
462
- entries = _.map(entries, (entry) => {
463
- try {
464
- let uid = entry.uid;
465
- let updatedEntry;
466
- // restores json rte entry refs if they exist
467
- if (self.ctJsonRte.indexOf(ctUid) > -1) {
468
- // the entries stored in eSuccessFilePath, have the same uids as the entries from source data
469
- updatedEntry = self.restoreJsonRteEntryRefs(entry, sourceStackEntries[entry.uid], schema.schema);
470
- }
471
- else {
472
- updatedEntry = entry;
473
- }
474
- let _entry = lookupEntries({
475
- content_type: schema,
476
- entry: updatedEntry,
477
- }, _.clone(self.mappedUids), refUidMapperPath);
478
- // if there's self references, the uid gets replaced
479
- _entry.uid = uid;
480
- return _entry;
481
- }
482
- catch (error) {
483
- addlogs(this.config, `Failed to update the entry '${uid}' references while reposting ${formatError(error)}`, 'error');
484
- }
485
- });
486
- log(this.config, 'Starting the reposting process for entries');
487
- const entryBatchLimit = this.eConfig.batchLimit || 10;
488
- const batchSize = Math.round(entryBatchLimit / 3);
489
- // Run entry creation in batches
490
- for (let i = 0; i < entries.length; i += batchSize) {
491
- batches.push(entries.slice(i, i + batchSize));
492
- }
493
- return Promise.map(batches, async (batch, index) => {
494
- return Promise.map(batch, async (entry) => {
495
- entry.uid = self.mappedUids[entry.uid];
496
- if (refsUpdatedUids.indexOf(entry.uid) !== -1) {
497
- log(this.config, 'Entry: ' +
498
- entry.uid +
499
- ' in Content Type: ' +
500
- ctUid +
501
- ' in lang: ' +
502
- lang +
503
- ' references fields are already updated.', 'success');
504
- return;
505
- }
506
- let promiseResult = new Promise((resolveUpdatedUids, rejectUpdatedUids) => {
507
- let entryResponse = self.stackAPIClient.contentType(ctUid).entry(entry.uid);
508
- Object.assign(entryResponse, entry);
509
- delete entryResponse.publish_details;
510
- return entryResponse
511
- .update({ locale: lang })
512
- .then((response) => {
513
- refsUpdatedUids.push(response.uid);
514
- return resolveUpdatedUids();
515
- })
516
- .catch((error) => {
517
- log(this.config, `Entry Uid '${entry.uid}' of Content Type '${ctUid}' failed to update in locale '${lang}'`, 'error');
518
- log(this.config, formatError(error), 'error');
519
- refsUpdateFailed.push({
520
- content_type: ctUid,
521
- entry: entry,
522
- locale: lang,
523
- error: error,
524
- });
525
- return rejectUpdatedUids(error);
526
- });
527
- });
528
- await promiseResult;
529
- }, {
530
- concurrency: this.importConcurrency,
531
- })
532
- .then(() => {
533
- // batch completed successfully
534
- fileHelper.writeFileSync(path.join(eFolderPath, 'success.json'), entries);
535
- fileHelper.writeFileSync(path.join(eFolderPath, 'refsUpdatedUids.json'), refsUpdatedUids);
536
- fileHelper.writeFileSync(path.join(eFolderPath, 'refsUpdateFailed.json'), refsUpdateFailed);
537
- log(this.config, 'Completed re-post entries batch no: ' + (index + 1) + ' successfully!', 'success');
538
- })
539
- .catch((error) => {
540
- // error while executing entry in batch
541
- addlogs(this.config, `Failed re-post entries at batch no: '${index + 1}`, 'error');
542
- addlogs(this.config, formatError(error), 'error');
543
- // throw error;
544
- });
545
- }, {
546
- concurrency: 1,
547
- })
548
- .then(() => {
549
- // finished updating entries with references
550
- log(this.config, "Imported entries of Content Type: '" + ctUid + "' in language: '" + lang + "' successfully!", 'success');
551
- })
552
- .catch((error) => {
553
- // error while updating entries with references
554
- addlogs(this.config, `Failed re-post entries of content type '${ctUid}' locale '${lang}'`, 'error');
555
- addlogs(this.config, formatError(error), 'error');
556
- // throw error;
557
- });
558
- }, {
559
- concurrency: 1,
560
- })
561
- .then(() => {
562
- // completed updating entry references
563
- log(this.config, chalk.green("Imported entries in '" + lang + "' language successfully!"), 'success');
564
- return resolve();
565
- })
566
- .catch((error) => {
567
- // error while updating entry references
568
- addlogs(this.config, chalk.red('Failed to re post entries in ' + lang + ' language'), 'error');
569
- return reject(error);
570
- });
571
- });
572
- }
573
- supressFields() {
574
- // it should be spelled as suppressFields
575
- log(this.config, 'Suppressing content type reference fields', 'success');
576
- let self = this;
577
- return new Promise(async (resolve, reject) => {
578
- let modifiedSchemas = [];
579
- let suppressedSchemas = [];
580
- for (let uid in self.ctSchemas) {
581
- if (uid) {
582
- let contentTypeSchema = _.cloneDeep(self.ctSchemas[uid]);
583
- let flag = {
584
- suppressed: false,
585
- references: false,
586
- jsonRte: false,
587
- jsonRteEmbeddedEntries: false,
588
- };
589
- if (contentTypeSchema.field_rules) {
590
- delete contentTypeSchema.field_rules;
591
- }
592
- // Set mandatory or unique flag to false
593
- suppressSchemaReference(contentTypeSchema.schema, flag);
594
- // Check if suppress modified flag
595
- if (flag.suppressed) {
596
- suppressedSchemas.push(contentTypeSchema);
597
- modifiedSchemas.push(self.ctSchemas[uid]);
598
- }
599
- if (flag.references) {
600
- self.refSchemas.push(uid);
601
- }
602
- if (flag.jsonRte) {
603
- self.ctJsonRte.push(uid);
604
- if (flag.jsonRteEmbeddedEntries) {
605
- self.ctJsonRteWithEntryRefs.push(uid);
606
- // pushing ct uid to refSchemas, because
607
- // repostEntries uses refSchemas content types for
608
- // reposting entries
609
- if (self.refSchemas.indexOf(uid) === -1) {
610
- self.refSchemas.push(uid);
611
- }
612
- }
613
- }
614
- // Replace extensions with new UID
615
- lookupExtension(this.config, contentTypeSchema.schema, this.config.preserveStackVersion, self.installedExtensions);
616
- }
617
- }
618
- // write modified schema in backup file
619
- fileHelper.writeFileSync(this.modifiedSchemaPath, modifiedSchemas);
620
- return Promise.map(suppressedSchemas, async (schema) => {
621
- let contentTypeResponse = self.stackAPIClient.contentType(schema.uid);
622
- Object.assign(contentTypeResponse, _.cloneDeep(schema));
623
- return contentTypeResponse
624
- .update()
625
- .then((_updatedcontentType) => {
626
- // empty function
627
- })
628
- .catch((_error) => {
629
- addlogs(this.config, formatError(_error), 'error');
630
- reject(`Failed suppress content type '${schema.uid}' reference fields`);
631
- });
632
- // update 5 content types at a time
633
- }, {
634
- // update reqConcurrency content types at a time
635
- concurrency: this.importConcurrency,
636
- })
637
- .then(() => {
638
- return resolve();
639
- })
640
- .catch((error) => {
641
- log(this.config, formatError(error), 'error');
642
- return reject('Failed to suppress reference fields in content type');
643
- });
644
- });
645
- }
646
- fetchEntry(query) {
647
- let self = this;
648
- return new Promise((resolve, _reject) => {
649
- let requestObject = {
650
- qs: {
651
- query: {
652
- title: query.entry.title,
653
- },
654
- locale: query.locale,
655
- },
656
- };
657
- return self.stackAPIClient
658
- .contentType(query.content_type)
659
- .entry()
660
- .query(requestObject.qs)
661
- .find()
662
- .then((response) => {
663
- if (response.body.entries.length <= 0) {
664
- log(this.config, 'Unable to map entry WO uid: ' + query.entry.uid, 'error');
665
- self.failedWO.push(query);
666
- return resolve();
667
- }
668
- self.mappedUids[query.entry.uid] = response.body.entries[0].uid;
669
- let _ePath = path.join(sanitizePath(this.entryMapperPath), sanitizePath(query.locale), sanitizePath(query.content_type), 'success.json');
670
- let entries = fileHelper.readFileSync(_ePath);
671
- entries.push(query.entry);
672
- fileHelper.writeFileSync(_ePath, entries);
673
- log(this.config, 'Completed mapping entry wo uid: ' + query.entry.uid + ': ' + response.body.entries[0].uid, 'clientsuccess');
674
- return resolve();
675
- })
676
- .catch((_error) => {
677
- return resolve();
678
- });
679
- });
680
- }
681
- unSuppressFields() {
682
- let self = this;
683
- return new Promise(async (resolve, reject) => {
684
- let modifiedSchemas = fileHelper.readFileSync(this.modifiedSchemaPath);
685
- let modifiedSchemasUids = [];
686
- let updatedExtensionUidsSchemas = [];
687
- for (let uid in modifiedSchemas) {
688
- if (uid) {
689
- let _contentTypeSchema = _.cloneDeep(modifiedSchemas[uid]);
690
- if (_contentTypeSchema.field_rules) {
691
- delete _contentTypeSchema.field_rules;
692
- }
693
- lookupExtension(this.config, _contentTypeSchema.schema, this.config.preserveStackVersion, self.installedExtensions);
694
- updatedExtensionUidsSchemas.push(_contentTypeSchema);
695
- }
696
- }
697
- return Promise.map(updatedExtensionUidsSchemas, async (schema) => {
698
- let promise = new Promise((resolveContentType, rejectContentType) => {
699
- self.stackAPIClient
700
- .contentType(schema.uid)
701
- .fetch()
702
- .then((contentTypeResponse) => {
703
- contentTypeResponse.schema = schema.schema;
704
- contentTypeResponse
705
- .update()
706
- .then((_updatedcontentType) => {
707
- modifiedSchemasUids.push(schema.uid);
708
- log(this.config, chalk.white("Content type: '" + schema.uid + "' has been restored to its previous glory!"));
709
- return resolveContentType();
710
- })
711
- .catch((error) => {
712
- addlogs(this.config, chalk.red('Failed to re-update ' + schema.uid), 'error');
713
- addlogs(this.config, error, 'error');
714
- return rejectContentType(error);
715
- });
716
- })
717
- .catch((error) => {
718
- log(this.config, error, 'error');
719
- return rejectContentType(error);
720
- });
721
- });
722
- await promise;
723
- }, {
724
- concurrency: this.reqConcurrency,
725
- })
726
- .then(() => {
727
- for (let i = 0; i < modifiedSchemas.length; i++) {
728
- if (modifiedSchemasUids.indexOf(modifiedSchemas[i].uid) !== -1) {
729
- modifiedSchemas.splice(i, 1);
730
- i--;
731
- }
732
- }
733
- // re-write, in case some schemas failed to update
734
- fileHelper.writeFileSync(this.modifiedSchemaPath, _.compact(modifiedSchemas));
735
- log(this.config, 'Re-modified content type schemas to their original form!', 'success');
736
- return resolve();
737
- })
738
- .catch((error) => {
739
- // failed to update modified schemas back to their original form
740
- return reject(error);
741
- });
742
- });
743
- }
744
- removeBuggedEntries() {
745
- let self = this;
746
- return new Promise((resolve, reject) => {
747
- let entries = fileHelper.readFileSync(this.uniqueUidMapperPath);
748
- let bugged = [];
749
- let removed = [];
750
- for (let uid in entries) {
751
- if (entries[uid].locales.indexOf(this.masterLanguage.code) === -1) {
752
- bugged.push({
753
- content_type: entries[uid].content_type,
754
- uid: uid,
755
- });
756
- }
757
- }
758
- return Promise.map(bugged, (entry) => {
759
- return self.stackAPIClient
760
- .contentType(entry.content_type)
761
- .entry(self.mappedUids[entry.uid])
762
- .delete({ locale: this.masterLanguage.code })
763
- .then(() => {
764
- removed.push(self.mappedUids[entry.uid]);
765
- log(this.config, 'Removed bugged entry from master ' + JSON.stringify(entry), 'success');
766
- })
767
- .catch((error) => {
768
- addlogs(this.config, chalk.red('Failed to remove bugged entry from master language'), 'error');
769
- addlogs(this.config, formatError(error), 'error');
770
- });
771
- }, {
772
- concurrency: this.importConcurrency,
773
- })
774
- .then(() => {
775
- for (let i = 0; i < bugged.length; i++) {
776
- if (removed.indexOf(bugged[i].uid) !== -1) {
777
- bugged.splice(i, 1);
778
- i--;
779
- }
780
- }
781
- fileHelper.writeFileSync(path.join(this.entryMapperPath, 'removed-uids.json'), removed);
782
- fileHelper.writeFileSync(path.join(this.entryMapperPath, 'pending-uids.json'), bugged);
783
- log(this.config, chalk.green('The stack has been eradicated from bugged entries!'), 'success');
784
- return resolve();
785
- })
786
- .catch((error) => {
787
- // error while removing bugged entries from stack
788
- addlogs(this.config, formatError(error), 'error');
789
- });
790
- });
791
- }
792
- field_rules_update(schema) {
793
- return new Promise((resolve, reject) => {
794
- if (schema.field_rules) {
795
- let fieldRuleLength = schema.field_rules.length;
796
- const fieldDatatypeMap = {};
797
- for (let i = 0; i < schema.schema.length; i++) {
798
- const field = schema.schema[i].uid;
799
- fieldDatatypeMap[field] = schema.schema[i].data_type;
800
- }
801
- for (let k = 0; k < fieldRuleLength; k++) {
802
- let fieldRuleConditionLength = schema.field_rules[k].conditions.length;
803
- for (let i = 0; i < fieldRuleConditionLength; i++) {
804
- if (fieldDatatypeMap[schema.field_rules[k].conditions[i].operand_field] === 'reference') {
805
- let fieldRulesValue = schema.field_rules[k].conditions[i].value;
806
- let fieldRulesArray = fieldRulesValue.split('.');
807
- let updatedValue = [];
808
- for (const element of fieldRulesArray) {
809
- let splitedFieldRulesValue = element;
810
- let oldUid = fileHelper.readFileSync(path.join(this.entryUidMapperPath));
811
- if (oldUid.hasOwnProperty(splitedFieldRulesValue)) {
812
- updatedValue.push(oldUid[splitedFieldRulesValue]);
813
- }
814
- else {
815
- updatedValue.push(element);
816
- }
817
- }
818
- schema.field_rules[k].conditions[i].value = updatedValue.join('.');
819
- }
820
- }
821
- }
822
- }
823
- else {
824
- log(this.config, 'field_rules is not available', 'error');
825
- }
826
- this.stackAPIClient
827
- .contentType(schema.uid)
828
- .fetch()
829
- .then((contentTypeResponse) => {
830
- // Object.assign(ctObj, _.cloneDeep(schema))
831
- contentTypeResponse.field_rules = schema.field_rules;
832
- return contentTypeResponse.update();
833
- })
834
- .then(() => {
835
- return resolve();
836
- })
837
- .catch((error) => {
838
- log(this.config, `failed to update the field rules ${formatError(error)}`);
839
- return reject(error);
840
- });
841
- });
842
- }
843
- publish(langs) {
844
- let self = this;
845
- let requestObject = {
846
- entry: {},
847
- };
848
- let contentTypeUids = Object.keys(self.ctSchemas);
849
- let entryMapper = fileHelper.readFileSync(this.entryUidMapperPath);
850
- return new Promise((resolve, reject) => {
851
- return Promise.map(langs, (_lang, counter) => {
852
- let lang = langs[counter];
853
- return Promise.map(contentTypeUids, async (ctUid) => {
854
- let eFilePath = path.resolve(this.ePath, ctUid, lang + '.json');
855
- let entries = await fileHelper.readLargeFile(eFilePath);
856
- if (entries === undefined) {
857
- addlogs(this.config, `No entries were found for Content type: ${ctUid} in language: ${lang}`, 'info');
858
- }
859
- else {
860
- let eUids = Object.keys(entries);
861
- let batches = [];
862
- let batchSize;
863
- if (eUids.length > 0) {
864
- let entryBatchLimit = this.eConfig.batchLimit || 10;
865
- batchSize = Math.round(entryBatchLimit / 3);
866
- // Run entry creation in batches
867
- for (let i = 0; i < eUids.length; i += batchSize) {
868
- batches.push(eUids.slice(i, i + batchSize));
869
- }
870
- }
871
- else {
872
- return;
873
- }
874
- return Promise.map(batches, async (batch, index) => {
875
- return Promise.map(batch, async (eUid) => {
876
- let entry = entries[eUid];
877
- let envId = [];
878
- let locales = [];
879
- if (entry.publish_details && entry.publish_details.length > 0) {
880
- _.forEach(entries[eUid].publish_details, (pubObject) => {
881
- if (self.environment.hasOwnProperty(pubObject.environment) &&
882
- _.indexOf(envId, self.environment[pubObject.environment].name) === -1) {
883
- envId.push(self.environment[pubObject.environment].name);
884
- }
885
- if (pubObject.locale) {
886
- let idx = _.indexOf(locales, pubObject.locale);
887
- if (idx === -1) {
888
- locales.push(pubObject.locale);
889
- }
890
- }
891
- });
892
- let entryUid = entryMapper[eUid];
893
- if (entryUid) {
894
- requestObject.entry.environments = envId;
895
- requestObject.entry.locales = locales;
896
- return new Promise((resolveEntryPublished, rejectEntryPublished) => {
897
- self.stackAPIClient
898
- .contentType(ctUid)
899
- .entry(entryUid)
900
- .publish({ publishDetails: requestObject.entry, locale: lang })
901
- // eslint-disable-next-line max-nested-callbacks
902
- .then((result) => {
903
- // addlogs(this.config, 'Entry ' + eUid + ' published successfully in ' + ctUid + ' content type', 'success')
904
- addlogs(this.config, `Entry '${eUid}' published successfully in '${ctUid}' content type`, 'success');
905
- return resolveEntryPublished(result);
906
- // eslint-disable-next-line max-nested-callbacks
907
- })
908
- .catch((err) => {
909
- addlogs(this.config, `failed to publish entry '${eUid}' content type '${ctUid}' ${formatError(err)}`, 'error');
910
- return resolveEntryPublished('');
911
- });
912
- });
913
- }
914
- }
915
- else {
916
- return {};
917
- }
918
- }, {
919
- concurrency: 1,
920
- })
921
- .then(() => {
922
- // empty function
923
- })
924
- .catch((error) => {
925
- // error while executing entry in batch
926
- addlogs(this.config, formatError(error), 'error');
927
- addlogs(this.config, error, 'error');
928
- });
929
- }, {
930
- concurrency: 1,
931
- })
932
- .then(() => {
933
- // addlogs(this.config, 'Entries published successfully in ' + ctUid + ' content type', 'success')
934
- addlogs(this.config, `Entries published successfully in '${ctUid}' content type`, 'info');
935
- })
936
- .catch((error) => {
937
- console.log(error);
938
- addlogs(this.config, `failed to publish entry in content type '${ctUid}' ${formatError(error)}`, 'error');
939
- });
940
- }
941
- }, {
942
- concurrency: 1,
943
- })
944
- .then(() => {
945
- // empty function
946
- // log('Published entries successfully in ' +);
947
- })
948
- .catch((error) => {
949
- addlogs(this.config, `Failed to publish few entries in ${lang} ${formatError(error)}`, 'error');
950
- });
951
- }, {
952
- concurrency: 1,
953
- })
954
- .then(() => {
955
- return resolve();
956
- })
957
- .catch((error) => {
958
- addlogs(this.config, `Failed to publish entries ${formatError(error)}`, 'error');
959
- });
960
- });
961
- }
962
- removeEntryRefsFromJSONRTE(entry, ctSchema) {
963
- for (const element of ctSchema) {
964
- switch (element.data_type) {
965
- case 'blocks': {
966
- if (entry[element.uid]) {
967
- if (element.multiple) {
968
- entry[element.uid] = entry[element.uid].map((e) => {
969
- let key = Object.keys(e).pop();
970
- let subBlock = element.blocks.filter((block) => block.uid === key).pop();
971
- e[key] = this.removeEntryRefsFromJSONRTE(e[key], subBlock.schema);
972
- return e;
973
- });
974
- }
975
- }
976
- break;
977
- }
978
- case 'global_field':
979
- case 'group': {
980
- if (entry[element.uid]) {
981
- if (element.multiple) {
982
- entry[element.uid] = entry[element.uid].map((e) => {
983
- e = this.removeEntryRefsFromJSONRTE(e, element.schema);
984
- return e;
985
- });
986
- }
987
- else {
988
- entry[element.uid] = this.removeEntryRefsFromJSONRTE(entry[element.uid], element.schema);
989
- }
990
- }
991
- break;
992
- }
993
- case 'json': {
994
- const structuredPTag = '{"type":"p","attrs":{},"children":[{"text":""}]}';
995
- if (entry[element.uid] && element.field_metadata.rich_text_type) {
996
- if (element.multiple) {
997
- entry[element.uid] = entry[element.uid].map((jsonRteData) => {
998
- // repeated code from else block, will abstract later
999
- let entryReferences = jsonRteData.children.filter((e) => this.doEntryReferencesExist(e));
1000
- if (entryReferences.length > 0) {
1001
- jsonRteData.children = jsonRteData.children.filter((e) => !this.doEntryReferencesExist(e));
1002
- if (jsonRteData.children.length === 0) {
1003
- jsonRteData.children.push(JSON.parse(structuredPTag));
1004
- }
1005
- return jsonRteData; // return jsonRteData without entry references
1006
- }
1007
- else {
1008
- return jsonRteData; // return jsonRteData as it is, because there are no entry references
1009
- }
1010
- });
1011
- }
1012
- else {
1013
- let entryReferences = entry[element.uid].children.filter((e) => this.doEntryReferencesExist(e));
1014
- if (entryReferences.length > 0) {
1015
- entry[element.uid].children = entry[element.uid].children.filter((e) => !this.doEntryReferencesExist(e));
1016
- if (entry[element.uid].children.length === 0) {
1017
- entry[element.uid].children.push(JSON.parse(structuredPTag));
1018
- }
1019
- }
1020
- }
1021
- }
1022
- break;
1023
- }
1024
- }
1025
- }
1026
- return entry;
1027
- }
1028
- doEntryReferencesExist(element) {
1029
- // checks if the children of p element contain any references
1030
- // only checking one level deep, not recursive
1031
- if (element.length) {
1032
- for (const item of element) {
1033
- if ((item.type === 'p' || item.type === 'a' || item.type === 'span') && item.children && item.children.length > 0) {
1034
- return this.doEntryReferencesExist(item.children);
1035
- }
1036
- else if (this.isEntryRef(item)) {
1037
- return true;
1038
- }
1039
- }
1040
- }
1041
- else {
1042
- if (this.isEntryRef(element)) {
1043
- return true;
1044
- }
1045
- if ((element.type === 'p' || element.type === 'a' || element.type === 'span') && element.children && element.children.length > 0) {
1046
- return this.doEntryReferencesExist(element.children);
1047
- }
1048
- }
1049
- return false;
1050
- }
1051
- restoreJsonRteEntryRefs(entry, sourceStackEntry, ctSchema) {
1052
- let mappedAssetUids = fileHelper.readFileSync(this.mappedAssetUidPath) || {};
1053
- let mappedAssetUrls = fileHelper.readFileSync(this.mappedAssetUrlPath) || {};
1054
- for (const element of ctSchema) {
1055
- switch (element.data_type) {
1056
- case 'blocks': {
1057
- if (entry[element.uid]) {
1058
- if (element.multiple) {
1059
- entry[element.uid] = entry[element.uid].map((e, eIndex) => {
1060
- let key = Object.keys(e).pop();
1061
- let subBlock = element.blocks.filter((block) => block.uid === key).pop();
1062
- let sourceStackElement = sourceStackEntry[element.uid][eIndex][key];
1063
- e[key] = this.restoreJsonRteEntryRefs(e[key], sourceStackElement, subBlock.schema);
1064
- return e;
1065
- });
1066
- }
1067
- }
1068
- break;
1069
- }
1070
- case 'global_field':
1071
- case 'group': {
1072
- if (entry[element.uid]) {
1073
- if (element.multiple) {
1074
- entry[element.uid] = entry[element.uid].map((e, eIndex) => {
1075
- let sourceStackElement = sourceStackEntry[element.uid][eIndex];
1076
- e = this.restoreJsonRteEntryRefs(e, sourceStackElement, element.schema);
1077
- return e;
1078
- });
1079
- }
1080
- else {
1081
- let sourceStackElement = sourceStackEntry[element.uid];
1082
- entry[element.uid] = this.restoreJsonRteEntryRefs(entry[element.uid], sourceStackElement, element.schema);
1083
- }
1084
- }
1085
- break;
1086
- }
1087
- case 'json': {
1088
- if (entry[element.uid] && element.field_metadata.rich_text_type) {
1089
- if (element.multiple) {
1090
- entry[element.uid] = entry[element.uid].map((field, index) => {
1091
- // i am facing a Maximum call stack exceeded issue,
1092
- // probably because of this loop operation
1093
- let entryRefs = sourceStackEntry[element.uid][index].children
1094
- .map((e, i) => {
1095
- return { index: i, value: e };
1096
- })
1097
- .filter((e) => this.doEntryReferencesExist(e.value))
1098
- .map((e) => {
1099
- // commenting the line below resolved the maximum call stack exceeded issue
1100
- // e.value = this.setDirtyTrue(e.value)
1101
- this.setDirtyTrue(e.value);
1102
- return e;
1103
- })
1104
- .map((e) => {
1105
- // commenting the line below resolved the maximum call stack exceeded issue
1106
- // e.value = this.resolveAssetRefsInEntryRefsForJsonRte(e, mappedAssetUids, mappedAssetUrls)
1107
- this.resolveAssetRefsInEntryRefsForJsonRte(e.value, mappedAssetUids, mappedAssetUrls);
1108
- return e;
1109
- });
1110
- if (entryRefs.length > 0) {
1111
- entryRefs.forEach((entryRef) => {
1112
- field.children.splice(entryRef.index, 0, entryRef.value);
1113
- });
1114
- }
1115
- return field;
1116
- });
1117
- }
1118
- else {
1119
- let entryRefs = sourceStackEntry[element.uid].children
1120
- .map((e, index) => {
1121
- return { index: index, value: e };
1122
- })
1123
- .filter((e) => this.doEntryReferencesExist(e.value))
1124
- .map((e) => {
1125
- this.setDirtyTrue(e.value);
1126
- return e;
1127
- })
1128
- .map((e) => {
1129
- this.resolveAssetRefsInEntryRefsForJsonRte(e.value, mappedAssetUids, mappedAssetUrls);
1130
- return e;
1131
- });
1132
- if (entryRefs.length > 0) {
1133
- entryRefs.forEach((entryRef) => {
1134
- if (!_.isEmpty(entry[element.uid]) && entry[element.uid].children) {
1135
- entry[element.uid].children.splice(entryRef.index, 0, entryRef.value);
1136
- }
1137
- });
1138
- }
1139
- }
1140
- }
1141
- break;
1142
- }
1143
- }
1144
- }
1145
- return entry;
1146
- }
1147
- isEntryRef(element) {
1148
- return element.type === 'reference' && element.attrs.type === 'entry';
1149
- }
1150
- removeUidsFromJsonRteFields(entry, ctSchema) {
1151
- for (const element of ctSchema) {
1152
- switch (element.data_type) {
1153
- case 'blocks': {
1154
- if (entry[element.uid]) {
1155
- if (element.multiple) {
1156
- entry[element.uid] = entry[element.uid].map((e) => {
1157
- let key = Object.keys(e).pop();
1158
- let subBlock = element.blocks.filter((block) => block.uid === key).pop();
1159
- e[key] = this.removeUidsFromJsonRteFields(e[key], subBlock.schema);
1160
- return e;
1161
- });
1162
- }
1163
- }
1164
- break;
1165
- }
1166
- case 'global_field':
1167
- case 'group': {
1168
- if (entry[element.uid]) {
1169
- if (element.multiple) {
1170
- entry[element.uid] = entry[element.uid].map((e) => {
1171
- e = this.removeUidsFromJsonRteFields(e, element.schema);
1172
- return e;
1173
- });
1174
- }
1175
- else {
1176
- entry[element.uid] = this.removeUidsFromJsonRteFields(entry[element.uid], element.schema);
1177
- }
1178
- }
1179
- break;
1180
- }
1181
- case 'json': {
1182
- if (entry[element.uid] && element.field_metadata.rich_text_type) {
1183
- if (element.multiple) {
1184
- entry[element.uid] = entry[element.uid].map((jsonRteData) => {
1185
- delete jsonRteData.uid; // remove uid
1186
- if (_.isObject(jsonRteData.attrs)) {
1187
- jsonRteData.attrs.dirty = true;
1188
- }
1189
- if (!_.isEmpty(jsonRteData.children)) {
1190
- jsonRteData.children = _.map(jsonRteData.children, (child) => this.removeUidsFromChildren(child));
1191
- }
1192
- return jsonRteData;
1193
- });
1194
- }
1195
- else {
1196
- delete entry[element.uid].uid; // remove uid
1197
- if (entry[element.uid] && _.isObject(entry[element.uid].attrs)) {
1198
- entry[element.uid].attrs.dirty = true;
1199
- }
1200
- if (entry[element.uid] && !_.isEmpty(entry[element.uid].children)) {
1201
- entry[element.uid].children = _.map(entry[element.uid].children, (child) => this.removeUidsFromChildren(child));
1202
- }
1203
- }
1204
- }
1205
- break;
1206
- }
1207
- }
1208
- }
1209
- return entry;
1210
- }
1211
- removeUidsFromChildren(children) {
1212
- if (children.length && children.length > 0) {
1213
- return children.map((child) => {
1214
- if (child.type && child.type.length > 0) {
1215
- delete child.uid; // remove uid
1216
- if (_.isObject(child.attrs)) {
1217
- child.attrs.dirty = true;
1218
- }
1219
- }
1220
- if (child.children && child.children.length > 0) {
1221
- child.children = this.removeUidsFromChildren(child.children);
1222
- }
1223
- return child;
1224
- });
1225
- }
1226
- else {
1227
- if (children.type && children.type.length > 0) {
1228
- delete children.uid; // remove uid
1229
- if (_.isObject(children.attrs)) {
1230
- children.attrs.dirty = true;
1231
- }
1232
- }
1233
- if (children.children && children.children.length > 0) {
1234
- children.children = this.removeUidsFromChildren(children.children);
1235
- }
1236
- return children;
1237
- }
1238
- }
1239
- setDirtyTrue(jsonRteChild) {
1240
- // also removing uids in this function
1241
- if (jsonRteChild.type) {
1242
- if (_.isObject(jsonRteChild.attrs)) {
1243
- jsonRteChild.attrs['dirty'] = true;
1244
- }
1245
- delete jsonRteChild.uid;
1246
- if (jsonRteChild.children && jsonRteChild.children.length > 0) {
1247
- jsonRteChild.children = jsonRteChild.children.map((subElement) => this.setDirtyTrue(subElement));
1248
- }
1249
- }
1250
- return jsonRteChild;
1251
- }
1252
- resolveAssetRefsInEntryRefsForJsonRte(jsonRteChild, mappedAssetUids, mappedAssetUrls) {
1253
- if (jsonRteChild.type) {
1254
- if (jsonRteChild.attrs.type === 'asset') {
1255
- let assetUrl;
1256
- if (mappedAssetUids[jsonRteChild.attrs['asset-uid']]) {
1257
- jsonRteChild.attrs['asset-uid'] = mappedAssetUids[jsonRteChild.attrs['asset-uid']];
1258
- }
1259
- if (jsonRteChild.attrs['display-type'] !== 'link') {
1260
- assetUrl = jsonRteChild.attrs['asset-link'];
1261
- }
1262
- else {
1263
- assetUrl = jsonRteChild.attrs['href'];
1264
- }
1265
- if (mappedAssetUrls[assetUrl]) {
1266
- if (jsonRteChild.attrs['display-type'] !== 'link') {
1267
- jsonRteChild.attrs['asset-link'] = mappedAssetUrls[assetUrl];
1268
- }
1269
- else {
1270
- jsonRteChild.attrs['href'] = mappedAssetUrls[assetUrl];
1271
- }
1272
- }
1273
- }
1274
- if (jsonRteChild.children && jsonRteChild.children.length > 0) {
1275
- jsonRteChild.children = jsonRteChild.children.map((subElement) => this.resolveAssetRefsInEntryRefsForJsonRte(subElement, mappedAssetUids, mappedAssetUrls));
1276
- }
1277
- }
1278
- return jsonRteChild;
1279
- }
1280
- };