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