@contentstack/cli-cm-import 0.1.1-beta.15 → 0.1.1-beta.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,6 +9,24 @@ It is Contentstack’s CLI plugin to import content in the stack. To learn how t
9
9
  * [Usage](#usage)
10
10
  * [Commands](#commands)
11
11
  <!-- tocstop -->
12
+
13
+ For switching to EU region update the hosts at config/default.js
14
+ ```js
15
+ {
16
+ host:'https://eu-api.contentstack.com/v3',
17
+ cdn: 'https://eu-cdn.contentstack.com/v3',
18
+ ...
19
+ }
20
+ ```
21
+
22
+ For switching to AZURE-NA region update the hosts at config/default.js
23
+ ```js
24
+ {
25
+ host:'https://azure-na-api.contentstack.com/v3',
26
+ cdn: 'https://azure-na-cdn.contentstack.com/v3'
27
+ ...
28
+ }
29
+ ```
12
30
  # Usage
13
31
  <!-- usage -->
14
32
  ```sh-session
@@ -16,7 +34,7 @@ $ npm install -g @contentstack/cli-cm-import
16
34
  $ csdx COMMAND
17
35
  running command...
18
36
  $ csdx (-v|--version|version)
19
- @contentstack/cli-cm-import/0.1.1-beta.15 linux-x64 node-v16.14.2
37
+ @contentstack/cli-cm-import/0.1.1-beta.18 linux-x64 node-v16.14.2
20
38
  $ csdx --help [COMMAND]
21
39
  USAGE
22
40
  $ csdx COMMAND
@@ -62,5 +80,5 @@ EXAMPLES
62
80
  csdx cm:import -A -B <branch name>
63
81
  ```
64
82
 
65
- _See code: [src/commands/cm/import.js](https://github.com/contentstack/cli/blob/v0.1.1-beta.15/packages/contentstack-import/src/commands/cm/import.js)_
83
+ _See code: [src/commands/cm/import.js](https://github.com/contentstack/cli/blob/v0.1.1-beta.18/packages/contentstack-import/src/commands/cm/import.js)_
66
84
  <!-- commandsstop -->
@@ -1 +1 @@
1
- {"version":"0.1.1-beta.15","commands":{"cm:import":{"id":"cm:import","description":"Import script for importing the content into new stack\n...\nOnce you export content from the source stack, import it to your destination stack by using the cm:import command.\n","pluginName":"@contentstack/cli-cm-import","pluginType":"core","aliases":[],"examples":["csdx cm:import -A","csdx cm:import -A -s <stack_ApiKey> -d <path/of/export/destination/dir>","csdx cm:import -A -c <path/of/config/dir>","csdx cm:import -A -m <single module name>","csdx cm:import -A -m <single module name> -b <backup dir>","csdx cm:import -a <management_token_alias>","csdx cm:import -a <management_token_alias> -d <path/of/export/destination/dir>","csdx cm:import -a <management_token_alias> -c <path/of/config/file>","csdx cm:import -A -m <single module name>","csdx cm:import -A -B <branch name>"],"flags":{"config":{"name":"config","type":"option","char":"c","description":"[optional] path of config file"},"stack-uid":{"name":"stack-uid","type":"option","char":"s","description":"API key of the target stack"},"data":{"name":"data","type":"option","char":"d","description":"path and location where data is stored"},"management-token-alias":{"name":"management-token-alias","type":"option","char":"a","description":"alias of the management token"},"auth-token":{"name":"auth-token","type":"boolean","char":"A","description":"to use auth token","allowNo":false},"module":{"name":"module","type":"option","char":"m","description":"[optional] specific module name"},"backup-dir":{"name":"backup-dir","type":"option","char":"b","description":"[optional] backup directory name when using specific module"},"branch":{"name":"branch","type":"option","char":"B","description":"[optional] branch name"}},"args":[]}}}
1
+ {"version":"0.1.1-beta.18","commands":{"cm:import":{"id":"cm:import","description":"Import script for importing the content into new stack\n...\nOnce you export content from the source stack, import it to your destination stack by using the cm:import command.\n","pluginName":"@contentstack/cli-cm-import","pluginType":"core","aliases":[],"examples":["csdx cm:import -A","csdx cm:import -A -s <stack_ApiKey> -d <path/of/export/destination/dir>","csdx cm:import -A -c <path/of/config/dir>","csdx cm:import -A -m <single module name>","csdx cm:import -A -m <single module name> -b <backup dir>","csdx cm:import -a <management_token_alias>","csdx cm:import -a <management_token_alias> -d <path/of/export/destination/dir>","csdx cm:import -a <management_token_alias> -c <path/of/config/file>","csdx cm:import -A -m <single module name>","csdx cm:import -A -B <branch name>"],"flags":{"config":{"name":"config","type":"option","char":"c","description":"[optional] path of config file"},"stack-uid":{"name":"stack-uid","type":"option","char":"s","description":"API key of the target stack"},"data":{"name":"data","type":"option","char":"d","description":"path and location where data is stored"},"management-token-alias":{"name":"management-token-alias","type":"option","char":"a","description":"alias of the management token"},"auth-token":{"name":"auth-token","type":"boolean","char":"A","description":"to use auth token","allowNo":false},"module":{"name":"module","type":"option","char":"m","description":"[optional] specific module name"},"backup-dir":{"name":"backup-dir","type":"option","char":"b","description":"[optional] backup directory name when using specific module"},"branch":{"name":"branch","type":"option","char":"B","description":"[optional] branch name"}},"args":[]}}}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@contentstack/cli-cm-import",
3
3
  "description": "Contentstack CLI plugin to import content into stack",
4
- "version": "0.1.1-beta.15",
4
+ "version": "0.1.1-beta.18",
5
5
  "author": "Contentstack",
6
6
  "bugs": "https://github.com/contentstack/cli/issues",
7
7
  "dependencies": {
@@ -38,8 +38,8 @@ class ImportCommand extends Command {
38
38
  moduleName,
39
39
  host,
40
40
  _authToken,
41
- branchName,
42
- backupdir
41
+ backupdir,
42
+ branchName
43
43
  )
44
44
  .then(() => {
45
45
  return resolve()
@@ -51,8 +51,8 @@ class ImportCommand extends Command {
51
51
  moduleName,
52
52
  host,
53
53
  _authToken,
54
- branchName,
55
- backupdir
54
+ backupdir,
55
+ branchName
56
56
  )
57
57
  .then(() => {
58
58
  return resolve()
@@ -63,8 +63,8 @@ class ImportCommand extends Command {
63
63
  moduleName,
64
64
  host,
65
65
  _authToken,
66
- branchName,
67
- backupdir
66
+ backupdir,
67
+ branchName
68
68
  )
69
69
  .then(() => {
70
70
  return resolve()
@@ -80,8 +80,8 @@ class ImportCommand extends Command {
80
80
  _authToken,
81
81
  moduleName,
82
82
  host,
83
- branchName,
84
- backupdir
83
+ backupdir,
84
+ branchName
85
85
  )
86
86
  .then(() => {
87
87
  return resolve()
@@ -1,5 +1,9 @@
1
1
  module.exports = {
2
2
  versioning: false,
3
+ // use below hosts for eu region
4
+ // host:'https://eu-api.contentstack.com/v3',
5
+ // use below hosts for azure-na region
6
+ // host:'https://azure-na-api.contentstack.com/v3',
3
7
  // pass locale, only to migrate entries from that locale
4
8
  // not passing `locale` will migrate all the locales present
5
9
  // locales: ['fr-fr'],
@@ -376,6 +376,7 @@ importAssets.prototype = {
376
376
  branch[parent_uid][coll[j].uid] = {}
377
377
  coll.splice(j, 1);
378
378
  self.findBranches(branch[parent_uid], coll)
379
+ --j
379
380
  }
380
381
  }
381
382
  }
@@ -191,6 +191,7 @@ importContentTypes.prototype = {
191
191
  // eslint-disable-next-line no-undef
192
192
  return Promise.map(globalFieldPendingPath, function (globalfield) {
193
193
  let Obj = _.find(self.globalfields, {uid: globalfield})
194
+ supress(Obj.schema)
194
195
  let globalFieldObj = stack.globalField(globalfield)
195
196
  Object.assign(globalFieldObj, _.cloneDeep(Obj))
196
197
  return globalFieldObj.update()
@@ -60,6 +60,12 @@ function importEntries() {
60
60
  this.ctSchemas = {}
61
61
  // Array of content type uids, that have reference fields
62
62
  this.refSchemas = []
63
+ // map of content types uids and their json-rte fields
64
+ this.ctJsonRte = []
65
+ // map of content types uids and their json-rte fields
66
+ this.ctJsonRteWithEntryRefs = []
67
+ // Entry refs that are held back to resolve after all entries have been created
68
+ this.jsonRteEntryRefs = {}
63
69
  // Collection of entries, that were not created, as they already exist on Stack
64
70
  this.createdEntriesWOUid = []
65
71
  // Collection of entry uids, mapped to the language they exist in
@@ -110,7 +116,7 @@ importEntries.prototype = {
110
116
  }
111
117
  }
112
118
 
113
- // Step 1: Removes filed rules from content type
119
+ // Step 1: Removes field rules from content type
114
120
  // This allows to handle cases like self references and circular reference
115
121
  // if mandatory reference fields are not filed in entries then avoids the error
116
122
  // Also remove field visibility rules
@@ -201,6 +207,18 @@ importEntries.prototype = {
201
207
  addlogs(config, `Creating entries for content type ${ctUid} in language ${lang} ...`, 'success')
202
208
  for (let eUid in entries) {
203
209
  if (eUid) {
210
+
211
+ // check ctUid in self.ctJsonRte array, if ct exists there... only then remove entry references for json rte
212
+ // also with json rte, api creates the json-rte field with the same uid as passed in the payload.
213
+
214
+ if (self.ctJsonRte.indexOf(ctUid) > -1) {
215
+ entries[eUid] = self.removeUidsFromJsonRteFields(entries[eUid], self.ctSchemas[ctUid].schema)
216
+ }
217
+
218
+ // remove entry references from json-rte fields
219
+ if (self.ctJsonRteWithEntryRefs.indexOf(ctUid) > -1) {
220
+ entries[eUid] = self.removeEntryRefsFromJSONRTE(entries[eUid], self.ctSchemas[ctUid].schema)
221
+ }
204
222
  // will replace all old asset uid/urls with new ones
205
223
  entries[eUid] = lookupReplaceAssets({
206
224
  content_type: self.ctSchemas[ctUid],
@@ -227,7 +245,7 @@ importEntries.prototype = {
227
245
  }) + ' as it is already created'), 'success')
228
246
  self.success[ctUid] = createdEntries[eUid]
229
247
  // if its a non-master language, i.e. the entry isn't present in the master language
230
- if (lang !== masterLanguage) {
248
+ if (lang !== masterLanguage.code) {
231
249
  self.uniqueUids[eUid] = self.uniqueUids[eUid] || {}
232
250
  if (self.uniqueUids[eUid].locales) {
233
251
  self.uniqueUids[eUid].locales.push(lang)
@@ -256,7 +274,7 @@ importEntries.prototype = {
256
274
  self.mappedUids[eUid] = entryResponse.uid
257
275
  createdEntries = entryResponse
258
276
  // if its a non-master language, i.e. the entry isn't present in the master language
259
- if (lang !== masterLanguage) {
277
+ if (lang !== masterLanguage.code) {
260
278
  self.uniqueUids[eUid] = self.uniqueUids[eUid] || {}
261
279
  if (self.uniqueUids[eUid].locales) {
262
280
  self.uniqueUids[eUid].locales.push(lang)
@@ -279,7 +297,7 @@ importEntries.prototype = {
279
297
  })
280
298
  }
281
299
  delete requestObject.json.entry.publish_details
282
- return client.stack({api_key: config.target_stack, management_token: config.management_token}).contentType(ctUid).entry().create(requestObject.json)
300
+ return client.stack({api_key: config.target_stack, management_token: config.management_token}).contentType(ctUid).entry().create(requestObject.json, {locale: lang})
283
301
  .then(async entryResponse => {
284
302
  self.success[ctUid] = self.success[ctUid] || []
285
303
  self.success[ctUid].push(entries[eUid])
@@ -287,7 +305,7 @@ importEntries.prototype = {
287
305
  self.mappedUids[eUid] = entryResponse.uid
288
306
  createdEntries = entryResponse
289
307
  // if its a non-master language, i.e. the entry isn't present in the master language
290
- if (lang !== masterLanguage) {
308
+ if (lang !== masterLanguage.code) {
291
309
  self.uniqueUids[eUid] = self.uniqueUids[eUid] || {}
292
310
  if (self.uniqueUids[eUid].locales) {
293
311
  self.uniqueUids[eUid].locales.push(lang)
@@ -393,6 +411,8 @@ importEntries.prototype = {
393
411
  return Promise.map(self.refSchemas, function (ctUid) {
394
412
  let eFolderPath = path.join(entryMapperPath, lang, ctUid)
395
413
  let eSuccessFilePath = path.join(eFolderPath, 'success.json')
414
+ let eFilePath = path.resolve(ePath, ctUid, lang + '.json')
415
+ let sourceStackEntries = helper.readFile(eFilePath)
396
416
 
397
417
  if (!fs.existsSync(eSuccessFilePath)) {
398
418
  addlogs(config, 'Success file was not found at: ' + eSuccessFilePath, 'success')
@@ -422,9 +442,19 @@ importEntries.prototype = {
422
442
  entries = _.map(entries, function (entry) {
423
443
  try {
424
444
  let uid = entry.uid
445
+ let updatedEntry
446
+
447
+ // restores json rte entry refs if they exist
448
+ if (self.ctJsonRte.indexOf(ctUid) > -1) {
449
+ // the entries stored in eSuccessFilePath, have the same uids as the entries from source data
450
+ updatedEntry = self.restoreJsonRteEntryRefs(entry, sourceStackEntries[entry.uid], schema.schema)
451
+ } else {
452
+ updatedEntry = entry
453
+ }
454
+
425
455
  let _entry = lookupReplaceEntries({
426
456
  content_type: schema,
427
- entry: entry,
457
+ entry: updatedEntry,
428
458
  }, _.clone(self.mappedUids), refUidMapperPath)
429
459
  // if there's self references, the uid gets replaced
430
460
  _entry.uid = uid
@@ -516,7 +546,7 @@ importEntries.prototype = {
516
546
  })
517
547
  })
518
548
  },
519
- supressFields: async function () {
549
+ supressFields: async function () { // it should be spelled as suppressFields
520
550
  addlogs(config, chalk.white('Suppressing content type fields...'), 'success')
521
551
  let self = this
522
552
  return new Promise(function (resolve, reject) {
@@ -529,6 +559,8 @@ importEntries.prototype = {
529
559
  let flag = {
530
560
  suppressed: false,
531
561
  references: false,
562
+ jsonRte: false,
563
+ jsonRteEmbeddedEntries: false
532
564
  }
533
565
  if (contentTypeSchema.field_rules) {
534
566
  delete contentTypeSchema.field_rules
@@ -546,6 +578,19 @@ importEntries.prototype = {
546
578
  self.refSchemas.push(uid)
547
579
  }
548
580
 
581
+ if (flag.jsonRte) {
582
+ self.ctJsonRte.push(uid)
583
+ if (flag.jsonRteEmbeddedEntries) {
584
+ self.ctJsonRteWithEntryRefs.push(uid)
585
+ // pushing ct uid to refSchemas, because
586
+ // repostEntries uses refSchemas content types for
587
+ // reposting entries
588
+ if (self.refSchemas.indexOf(uid) === -1) {
589
+ self.refSchemas.push(uid)
590
+ }
591
+ }
592
+ }
593
+
549
594
  // Replace extensions with new UID
550
595
  extension_suppress(contentTypeSchema.schema, config.preserveStackVersion)
551
596
  }
@@ -851,6 +896,301 @@ importEntries.prototype = {
851
896
  })
852
897
  })
853
898
  },
899
+ removeEntryRefsFromJSONRTE: function(entry, ctSchema) {
900
+ for (let i = 0; i < ctSchema.length; i++) {
901
+ switch(ctSchema[i].data_type) {
902
+ case 'blocks': {
903
+ if (entry[ctSchema[i].uid]) {
904
+ if (ctSchema[i].multiple) {
905
+ entry[ctSchema[i].uid] = entry[ctSchema[i].uid].map(e => {
906
+ let key = Object.keys(e).pop()
907
+ let subBlock = ctSchema[i].blocks.filter(e => e.uid === key).pop()
908
+ e[key] = this.removeEntryRefsFromJSONRTE(e[key], subBlock.schema)
909
+ return e
910
+ })
911
+ }
912
+ }
913
+ break;
914
+ }
915
+ case 'global_field':
916
+ case 'group': {
917
+ if (entry[ctSchema[i].uid]) {
918
+ if (ctSchema[i].multiple) {
919
+ entry[ctSchema[i].uid] = entry[ctSchema[i].uid].map(e => {
920
+ e = this.removeEntryRefsFromJSONRTE(e, ctSchema[i].schema)
921
+ return e
922
+ })
923
+ } else {
924
+ entry[ctSchema[i].uid] = this.removeEntryRefsFromJSONRTE(entry[ctSchema[i].uid], ctSchema[i].schema)
925
+ }
926
+ }
927
+ break;
928
+ }
929
+ case 'json': {
930
+ if (entry[ctSchema[i].uid] && ctSchema[i].field_metadata.rich_text_type) {
931
+ if (ctSchema[i].multiple) {
932
+ entry[ctSchema[i].uid] = entry[ctSchema[i].uid].map(jsonRteData => {
933
+ // repeated code from else block, will abstract later
934
+ let entryReferences = jsonRteData.children.filter(e => this.doEntryReferencesExist(e))
935
+ if (entryReferences.length > 0) {
936
+ jsonRteData.children = jsonRteData.children.filter(e => !this.doEntryReferencesExist(e))
937
+ return jsonRteData // return jsonRteData without entry references
938
+ } else {
939
+ return jsonRteData // return jsonRteData as it is, because there are no entry references
940
+ }
941
+ })
942
+ } else {
943
+ let entryReferences = entry[ctSchema[i].uid].children.filter(e => this.doEntryReferencesExist(e))
944
+ if (entryReferences.length > 0) {
945
+ entry[ctSchema[i].uid].children = entry[ctSchema[i].uid].children.filter(e => !this.doEntryReferencesExist(e))
946
+ }
947
+ }
948
+ }
949
+ break;
950
+ }
951
+ }
952
+ }
953
+ return entry
954
+ },
955
+ doEntryReferencesExist: function(element) {
956
+ // checks if the children of p element contain any references
957
+ // only checking one level deep, not recursive
958
+
959
+ if (element.length) {
960
+ for(let i=0; i < element.length; i++) {
961
+ if((element[i].type === 'p' || element[i].type === 'a') && element[i].children && element[i].children.length > 0) {
962
+ return this.doEntryReferencesExist(element[i].children)
963
+ } else if(this.isEntryRef(element[i])) {
964
+ return true
965
+ }
966
+ }
967
+ } else {
968
+ if(this.isEntryRef(element)) {
969
+ return true
970
+ }
971
+
972
+ if ((element.type === 'p' || element.type === 'a') && element.children && element.children.length > 0) {
973
+ return this.doEntryReferencesExist(element.children)
974
+ }
975
+ }
976
+ return false
977
+ },
978
+ restoreJsonRteEntryRefs: function(entry, sourceStackEntry, ctSchema) {
979
+ let mappedAssetUids = helper.readFile(mappedAssetUidPath) || {}
980
+ let mappedAssetUrls = helper.readFile(mappedAssetUrlPath) || {}
981
+ for (let i = 0; i < ctSchema.length; i++) {
982
+ switch (ctSchema[i].data_type) {
983
+ case 'blocks': {
984
+ if (entry[ctSchema[i].uid]) {
985
+ if (ctSchema[i].multiple) {
986
+ entry[ctSchema[i].uid] = entry[ctSchema[i].uid].map((e, eIndex) => {
987
+ let key = Object.keys(e).pop()
988
+ let subBlock = ctSchema[i].blocks.filter(e => e.uid === key).pop()
989
+ let sourceStackElement = sourceStackEntry[ctSchema[i].uid][eIndex][key]
990
+ e[key] = this.restoreJsonRteEntryRefs(e[key], sourceStackElement, subBlock.schema)
991
+ return e
992
+ })
993
+ }
994
+ }
995
+ break;
996
+ }
997
+ case 'global_field':
998
+ case 'group': {
999
+ if (entry[ctSchema[i].uid]) {
1000
+ if (ctSchema[i].multiple) {
1001
+ entry[ctSchema[i].uid] = entry[ctSchema[i].uid].map((e, eIndex) => {
1002
+ let sourceStackElement = sourceStackEntry[ctSchema[i].uid][eIndex]
1003
+ e = this.restoreJsonRteEntryRefs(e, sourceStackElement, ctSchema[i].schema)
1004
+ return e
1005
+ })
1006
+ } else {
1007
+ let sourceStackElement = sourceStackEntry[ctSchema[i].uid]
1008
+ entry[ctSchema[i].uid] = this.restoreJsonRteEntryRefs(entry[ctSchema[i].uid], sourceStackElement, ctSchema[i].schema)
1009
+ }
1010
+ }
1011
+ break;
1012
+ }
1013
+ case 'json': {
1014
+ if (entry[ctSchema[i].uid] && ctSchema[i].field_metadata.rich_text_type) {
1015
+ if (ctSchema[i].multiple) {
1016
+ entry[ctSchema[i].uid] = entry[ctSchema[i].uid].map((field, index) => {
1017
+
1018
+ // i am facing a Maximum call stack exceeded issue,
1019
+ // probably because of this loop operation
1020
+
1021
+ let entryRefs = sourceStackEntry[ctSchema[i].uid][index].children
1022
+ .map((e, index) => {
1023
+ return { index: index, value: e }
1024
+ })
1025
+ .filter(e => this.doEntryReferencesExist(e.value))
1026
+ .map(e => {
1027
+ // commenting the line below resolved the maximum call stack exceeded issue
1028
+ // e.value = this.setDirtyTrue(e.value)
1029
+ this.setDirtyTrue(e.value)
1030
+ return e
1031
+ })
1032
+ .map(e => {
1033
+ // commenting the line below resolved the maximum call stack exceeded issue
1034
+ // e.value = this.resolveAssetRefsInEntryRefsForJsonRte(e, mappedAssetUids, mappedAssetUrls)
1035
+ this.resolveAssetRefsInEntryRefsForJsonRte(e.value, mappedAssetUids, mappedAssetUrls)
1036
+ return e
1037
+ })
1038
+
1039
+ if(entryRefs.length > 0) {
1040
+ entryRefs.forEach(element => {
1041
+ field.children.splice(element.index, 0, element.value)
1042
+ })
1043
+ }
1044
+ return field
1045
+ })
1046
+ } else {
1047
+
1048
+ let entryRefs = sourceStackEntry[ctSchema[i].uid].children
1049
+ .map((e, index) => {
1050
+ return { index: index, value: e }
1051
+ })
1052
+ .filter(e => this.doEntryReferencesExist(e.value))
1053
+ .map(e => {
1054
+ this.setDirtyTrue(e.value)
1055
+ return e
1056
+ })
1057
+ .map(e => {
1058
+ this.resolveAssetRefsInEntryRefsForJsonRte(e.value, mappedAssetUids, mappedAssetUrls)
1059
+ return e
1060
+ })
1061
+
1062
+ if(entryRefs.length > 0) {
1063
+ entryRefs.forEach(element => {
1064
+ entry[ctSchema[i].uid].children.splice(element.index, 0, element.value)
1065
+ })
1066
+ }
1067
+ }
1068
+ }
1069
+ break;
1070
+ }
1071
+ }
1072
+ }
1073
+ return entry
1074
+ },
1075
+ isEntryRef: function(element) {
1076
+ return element.type === "reference" && element.attrs.type === "entry"
1077
+ },
1078
+ removeUidsFromJsonRteFields: function(entry, ctSchema) {
1079
+ for (let i = 0; i < ctSchema.length; i++) {
1080
+ switch (ctSchema[i].data_type) {
1081
+ case 'blocks': {
1082
+ if (entry[ctSchema[i].uid]) {
1083
+ if (ctSchema[i].multiple) {
1084
+ entry[ctSchema[i].uid] = entry[ctSchema[i].uid].map(e => {
1085
+ let key = Object.keys(e).pop()
1086
+ let subBlock = ctSchema[i].blocks.filter(e => e.uid === key).pop()
1087
+ e[key] = this.removeUidsFromJsonRteFields(e[key], subBlock.schema)
1088
+ return e
1089
+ })
1090
+ }
1091
+ }
1092
+ break;
1093
+ }
1094
+ case 'global_field':
1095
+ case 'group': {
1096
+ if (entry[ctSchema[i].uid]) {
1097
+ if (ctSchema[i].multiple) {
1098
+ entry[ctSchema[i].uid] = entry[ctSchema[i].uid].map(e => {
1099
+ e = this.removeUidsFromJsonRteFields(e, ctSchema[i].schema)
1100
+ return e
1101
+ })
1102
+ } else {
1103
+ entry[ctSchema[i].uid] = this.removeUidsFromJsonRteFields(entry[ctSchema[i].uid], ctSchema[i].schema)
1104
+ }
1105
+ }
1106
+ break;
1107
+ }
1108
+ case 'json': {
1109
+ if (entry[ctSchema[i].uid] && ctSchema[i].field_metadata.rich_text_type) {
1110
+ if (ctSchema[i].multiple) {
1111
+ entry[ctSchema[i].uid] = entry[ctSchema[i].uid].map(jsonRteData => {
1112
+ delete jsonRteData.uid // remove uid
1113
+ jsonRteData.attrs.dirty = true
1114
+ jsonRteData.children = jsonRteData.children.map(child => this.removeUidsFromChildren(child))
1115
+ return jsonRteData
1116
+ })
1117
+ } else {
1118
+ delete entry[ctSchema[i].uid].uid // remove uid
1119
+ entry[ctSchema[i].uid].attrs.dirty = true
1120
+ entry[ctSchema[i].uid].children = entry[ctSchema[i].uid].children.map(child => this.removeUidsFromChildren(child))
1121
+ }
1122
+ }
1123
+ break;
1124
+ }
1125
+ }
1126
+ }
1127
+ return entry
1128
+ },
1129
+ removeUidsFromChildren: function(children) {
1130
+ if (children.length && children.length > 0) {
1131
+ return children.map(child => {
1132
+ if(child.type && child.type.length > 0) {
1133
+ delete child.uid // remove uid
1134
+ child.attrs.dirty = true
1135
+ }
1136
+ if(child.children && child.children.length > 0) {
1137
+ child.children = this.removeUidsFromChildren(child.children)
1138
+ }
1139
+ return child
1140
+ })
1141
+ } else {
1142
+ if (children.type && children.type.length > 0) {
1143
+ delete children.uid // remove uid
1144
+ children.attrs.dirty = true
1145
+ }
1146
+ if (children.children && children.children.length > 0) {
1147
+ children.children = this.removeUidsFromChildren(children.children)
1148
+ }
1149
+ return children
1150
+ }
1151
+ },
1152
+ setDirtyTrue: function(jsonRteChild) { // also removing uids in this function
1153
+ if (jsonRteChild.type) {
1154
+ jsonRteChild.attrs['dirty'] = true
1155
+ delete jsonRteChild.uid
1156
+
1157
+ if (jsonRteChild.children && jsonRteChild.children.length > 0) {
1158
+ jsonRteChild.children = jsonRteChild.children.map(subElement => this.setDirtyTrue(subElement))
1159
+ }
1160
+ }
1161
+ return jsonRteChild
1162
+ },
1163
+ resolveAssetRefsInEntryRefsForJsonRte: function(jsonRteChild, mappedAssetUids, mappedAssetUrls) {
1164
+
1165
+ if (jsonRteChild.type) {
1166
+ if (jsonRteChild.attrs.type === 'asset') {
1167
+ let assetUrl
1168
+ if(mappedAssetUids[jsonRteChild.attrs['asset-uid']]) {
1169
+ jsonRteChild.attrs['asset-uid'] = mappedAssetUids[jsonRteChild.attrs['asset-uid']]
1170
+ }
1171
+
1172
+ if (jsonRteChild.attrs['display-type'] !== 'link') {
1173
+ assetUrl = jsonRteChild.attrs['asset-link']
1174
+ } else {
1175
+ assetUrl = jsonRteChild.attrs['href']
1176
+ }
1177
+
1178
+ if(mappedAssetUrls[assetUrl]) {
1179
+ if (jsonRteChild.attrs['display-type'] !== 'link') {
1180
+ jsonRteChild.attrs['asset-link'] = mappedAssetUrls[assetUrl]
1181
+ } else {
1182
+ jsonRteChild.attrs['href'] = mappedAssetUrls[assetUrl]
1183
+ }
1184
+ }
1185
+ }
1186
+
1187
+ if (jsonRteChild.children && jsonRteChild.children.length > 0) {
1188
+ jsonRteChild.children = jsonRteChild.children.map(subElement => this.resolveAssetRefsInEntryRefsForJsonRte(subElement, mappedAssetUids, mappedAssetUrls))
1189
+ }
1190
+ }
1191
+
1192
+ return jsonRteChild
1193
+ }
854
1194
  }
855
1195
 
856
1196
  module.exports = new importEntries()
@@ -76,7 +76,7 @@ importExtensions.prototype = {
76
76
  })
77
77
  }
78
78
  // the extensions has already been created
79
- addlogs(config, chalk.white('The extension: \'' + ext.name +
79
+ addlogs(config, chalk.white('The extension: \'' + ext.title +
80
80
  '\' already exists. Skipping it to avoid duplicates!'), 'success')
81
81
  // import 2 extensions at a time
82
82
  }, {
@@ -1,4 +1,7 @@
1
1
  const contentstacksdk = require("@contentstack/management");
2
+ const https = require("https");
3
+
4
+ const { addlogs } = require("./log");
2
5
 
3
6
  exports.Client = function (config) {
4
7
  const option = {
@@ -8,6 +11,17 @@ exports.Client = function (config) {
8
11
  api_key: config.target_stack,
9
12
  maxContentLength: 100000000,
10
13
  maxBodyLength: 1000000000,
14
+ maxRequests: 10,
15
+ retryLimit: 5,
16
+ timeout: 60000,
17
+ httpsAgent: new https.Agent({
18
+ maxSockets: 100,
19
+ maxFreeSockets: 10,
20
+ keepAlive: true,
21
+ timeout: 60000, // active socket keepalive for 60 seconds
22
+ freeSocketTimeout: 30000, // free socket keepalive for 30 seconds
23
+ }),
24
+ retryDelay: Math.floor(Math.random() * (8000 - 3000 + 1) + 3000),
11
25
  logHandler: (level, data) => {},
12
26
  retryCondition: (error) => {
13
27
  // no async function should be used here
@@ -22,12 +36,12 @@ exports.Client = function (config) {
22
36
  retryDelayOptions: {
23
37
  base: 1000,
24
38
  },
25
- }
26
- if (typeof config.branchName === 'string') {
39
+ };
40
+ if (typeof config.branchName === "string") {
27
41
  option.headers = {
28
42
  branch: config.branchName,
29
- }
43
+ };
30
44
  }
31
- const client = contentstacksdk.client(option)
32
- return client
33
- }
45
+ const client = contentstacksdk.client(option);
46
+ return client;
47
+ };
@@ -30,7 +30,7 @@ module.exports = function (data, mappedAssetUids, mappedAssetUrls, assetUidMappe
30
30
  if ((schema[i].data_type === 'text' && schema[i].field_metadata && (schema[i].field_metadata.markdown ||
31
31
  schema[i].field_metadata.rich_text_type))) {
32
32
  parent.push(schema[i].uid);
33
- findFileUrls(parent, schema[i], entry, assetUrls);
33
+ findFileUrls(schema[i], entry, assetUrls);
34
34
  parent.pop();
35
35
  }
36
36
  if (schema[i].data_type === 'group' || schema[i].data_type === 'global_field') {
@@ -49,35 +49,128 @@ module.exports = function (data, mappedAssetUids, mappedAssetUrls, assetUidMappe
49
49
  }
50
50
  }
51
51
  }
52
+ // added rich_text_type field check because some marketplace extensions also
53
+ // have data_type has json
54
+ if (schema[i].data_type === "json" && schema[i].field_metadata.rich_text_type) {
55
+ parent.push(schema[i].uid)
56
+ // findFileUrls(schema[i], entry, assetUrls)
57
+ findAssetIdsFromJsonRte(data.entry, data.content_type.schema)
58
+ // maybe only one of these checks would be enough
59
+ parent.pop()
60
+ }
52
61
  }
53
62
  };
63
+
64
+ function findAssetIdsFromJsonRte(entry, ctSchema) {
65
+ for (let i = 0; i < ctSchema.length; i++) {
66
+ switch (ctSchema[i].data_type) {
67
+ case 'blocks': {
68
+ if (entry[ctSchema[i].uid]) {
69
+ if (ctSchema[i].multiple) {
70
+ entry[ctSchema[i].uid].forEach(e => {
71
+ let key = Object.keys(e).pop()
72
+ let subBlock = ctSchema[i].blocks.filter(e => e.uid === key).pop()
73
+ findAssetIdsFromJsonRte(e[key], subBlock.schema)
74
+ })
75
+ }
76
+ }
77
+ break;
78
+ }
79
+ case 'global_field':
80
+ case 'group': {
81
+ if (entry[ctSchema[i].uid]) {
82
+ if (ctSchema[i].multiple) {
83
+ entry[ctSchema[i].uid].forEach(e => {
84
+ findAssetIdsFromJsonRte(e, ctSchema[i].schema)
85
+ })
86
+ } else {
87
+ findAssetIdsFromJsonRte(entry[ctSchema[i].uid], ctSchema[i].schema)
88
+ }
89
+ }
90
+ break;
91
+ }
92
+ case 'json': {
93
+ if (entry[ctSchema[i].uid] && ctSchema[i].field_metadata.rich_text_type) {
94
+ if (ctSchema[i].multiple) {
95
+ entry[ctSchema[i].uid].forEach(jsonRteData => {
96
+ gatherJsonRteAssetIds(jsonRteData)
97
+ })
98
+ } else {
99
+ gatherJsonRteAssetIds(entry[ctSchema[i].uid])
100
+ }
101
+ }
102
+ break;
103
+ }
104
+ }
105
+ }
106
+ }
54
107
 
55
-
108
+ function gatherJsonRteAssetIds(jsonRteData) {
109
+ jsonRteData.children.forEach(element => {
110
+ if (element.type) {
111
+ switch (element.type) {
112
+ case 'a':
113
+ case 'p': {
114
+ if (element.children && element.children.length > 0) {
115
+ gatherJsonRteAssetIds(element)
116
+ }
117
+ break;
118
+ }
119
+ case 'reference': {
120
+ if (Object.keys(element.attrs).length > 0 && element.attrs.type === "asset") {
121
+ if (assetUids.indexOf(element.attrs['asset-uid']) === -1) {
122
+ assetUids.push(element.attrs['asset-uid'])
123
+ }
124
+ // assets references inserted as link inside entry reference inserted as link did not have asset-link property
125
+ // instead it had an 'href' property. I haven't seen 'asset-link' and 'href' together yet
126
+ // writing this condition assuming that this never occurs, need to confirm
127
+ // (element.attrs['asset-link']) ? assetUrls.push(element.attrs['asset-link']) : assetUrls.push(element.attrs['asset-link'])
128
+ if (element.attrs['asset-link']) {
129
+ if (assetUrls.indexOf(element.attrs['asset-link']) === -1) {
130
+ assetUrls.push(element.attrs['asset-link'])
131
+ }
132
+ } else if (element.attrs['href']) {
133
+ if (assetUrls.indexOf(element.attrs['href']) === -1) {
134
+ assetUrls.push(element.attrs['href'])
135
+ }
136
+ }
137
+ }
138
+ if (element.children && element.children.length > 0) {
139
+ gatherJsonRteAssetIds(element)
140
+ }
141
+ break;
142
+ }
143
+ }
144
+ }
145
+ })
146
+ }
147
+
56
148
  find(data.content_type.schema, data.entry);
57
149
  updateFileFields(data.entry, data, null, mappedAssetUids, matchedUids, unmatchedUids);
58
150
  assetUids = _.uniq(assetUids);
59
151
  assetUrls = _.uniq(assetUrls);
60
152
  var entry = JSON.stringify(data.entry);
61
- assetUids.forEach(function (assetUid) {
62
- var uid = mappedAssetUids[assetUid];
63
- if (typeof uid !== 'undefined') {
64
- entry = entry.replace(new RegExp(assetUid, 'img'), uid);
65
- matchedUids.push(assetUid);
66
- } else {
67
- unmatchedUids.push(assetUid);
68
- }
69
- });
70
153
 
71
154
  assetUrls.forEach(function (assetUrl) {
72
155
  var url = mappedAssetUrls[assetUrl];
73
156
  if (typeof url !== 'undefined') {
74
157
  entry = entry.replace(new RegExp(assetUrl, 'img'), url);
75
- unmatchedUrls.push(url);
158
+ matchedUrls.push(url);
76
159
  } else {
77
160
  unmatchedUrls.push(assetUrl);
78
161
  }
79
162
  });
80
163
 
164
+ assetUids.forEach(function (assetUid) {
165
+ var uid = mappedAssetUids[assetUid];
166
+ if (typeof uid !== 'undefined') {
167
+ entry = entry.replace(new RegExp(assetUid, 'img'), uid);
168
+ matchedUids.push(assetUid);
169
+ } else {
170
+ unmatchedUids.push(assetUid);
171
+ }
172
+ });
173
+
81
174
  if (matchedUids.length) {
82
175
  var matchedAssetUids = helper.readFile(path.join(assetUidMapperPath, 'matched-asset-uids.json'));
83
176
  matchedAssetUids = matchedAssetUids || {};
@@ -158,11 +251,11 @@ function findFileUrls (schema, _entry, assetUrls) {
158
251
  var text;
159
252
  // Regex to detect v3 asset uri patterns
160
253
  if (schema && schema.field_metadata && schema.field_metadata.markdown) {
161
- text = marked(_entry);
254
+ text = marked(JSON.stringify(_entry));
162
255
  } else {
163
- text = _entry;
256
+ text = JSON.stringify(_entry);
164
257
  }
165
- markdownRegEx = new RegExp('(https://(assets|images).contentstack.io/v3/assets/(.*?)/(.*?)/(.*?)/(.*)(?="))', 'g');
258
+ markdownRegEx = new RegExp('(https://(assets|(eu-|azure-na-|stag-)?images).contentstack.(io|com)/v3/assets/(.*?)/(.*?)/(.*?)/(.*?)(?="))', 'g');
166
259
  while ((markdownMatch = markdownRegEx.exec(text)) !== null) {
167
260
  if (markdownMatch && typeof markdownMatch[0] === 'string') {
168
261
  assetUrls.push(markdownMatch[0]);
@@ -21,6 +21,33 @@ module.exports = function (data, mappedUids, uidMapperPath) {
21
21
  var isNewRefFields = false
22
22
  var preserveStackVersion = config.preserveStackVersion
23
23
 
24
+ function gatherJsonRteEntryIds(jsonRteData) {
25
+ jsonRteData.children.forEach(element => {
26
+ if (element.type) {
27
+ switch (element.type) {
28
+ case 'a':
29
+ case 'p': {
30
+ if (element.children && element.children.length > 0) {
31
+ gatherJsonRteEntryIds(element)
32
+ }
33
+ break;
34
+ }
35
+ case 'reference': {
36
+ if (Object.keys(element.attrs).length > 0 && element.attrs.type === "entry") {
37
+ if (uids.indexOf(element.attrs['entry-uid']) === -1) {
38
+ uids.push(element.attrs['entry-uid'])
39
+ }
40
+ }
41
+ if (element.children && element.children.length > 0) {
42
+ gatherJsonRteEntryIds(element)
43
+ }
44
+ break;
45
+ }
46
+ }
47
+ }
48
+ })
49
+ }
50
+
24
51
  var update = function (parent, form_id, entry) {
25
52
  var _entry = entry
26
53
  var len = parent.length
@@ -83,6 +110,7 @@ module.exports = function (data, mappedUids, uidMapperPath) {
83
110
  parent.pop()
84
111
  }
85
112
  break
113
+ case 'global_field':
86
114
  case 'group':
87
115
  parent.push(schema[i].uid)
88
116
  find(schema[i].schema, entry)
@@ -97,9 +125,59 @@ module.exports = function (data, mappedUids, uidMapperPath) {
97
125
  parent.pop()
98
126
  }
99
127
  break
128
+ case 'json':
129
+ if (schema[i].field_metadata.rich_text_type) {
130
+ findEntryIdsFromJsonRte(data.entry, data.content_type.schema)
131
+ }
132
+ break
100
133
  }
101
134
  }
102
135
  }
136
+
137
+ function findEntryIdsFromJsonRte(entry, ctSchema) {
138
+ for (let i = 0; i < ctSchema.length; i++) {
139
+ switch (ctSchema[i].data_type) {
140
+ case 'blocks': {
141
+ if (entry[ctSchema[i].uid]) {
142
+ if (ctSchema[i].multiple) {
143
+ entry[ctSchema[i].uid].forEach(e => {
144
+ let key = Object.keys(e).pop()
145
+ let subBlock = ctSchema[i].blocks.filter(e => e.uid === key).pop()
146
+ findEntryIdsFromJsonRte(e[key], subBlock.schema)
147
+ })
148
+ }
149
+ }
150
+ break;
151
+ }
152
+ case 'global_field':
153
+ case 'group': {
154
+ if (entry[ctSchema[i].uid]) {
155
+ if (ctSchema[i].multiple) {
156
+ entry[ctSchema[i].uid].forEach(e => {
157
+ findEntryIdsFromJsonRte(e, ctSchema[i].schema)
158
+ })
159
+ } else {
160
+ findEntryIdsFromJsonRte(entry[ctSchema[i].uid], ctSchema[i].schema)
161
+ }
162
+ }
163
+ break;
164
+ }
165
+ case 'json': {
166
+ if (entry[ctSchema[i].uid] && ctSchema[i].field_metadata.rich_text_type) {
167
+ if (ctSchema[i].multiple) {
168
+ entry[ctSchema[i].uid].forEach(jsonRteData => {
169
+ gatherJsonRteEntryIds(jsonRteData)
170
+ })
171
+ } else {
172
+ gatherJsonRteEntryIds(entry[ctSchema[i].uid])
173
+ }
174
+ }
175
+ break;
176
+ }
177
+ }
178
+ }
179
+ }
180
+
103
181
  find(data.content_type.schema, data.entry)
104
182
  if (isNewRefFields) {
105
183
  findUidsInNewRefFields(data.entry, uids)
@@ -35,6 +35,13 @@ var removeReferenceFields = module.exports = function (schema, flag) {
35
35
  'non_localizable': false
36
36
  });
37
37
  }
38
- }
38
+ } else if( // handling entry references in json rte
39
+ schema[i].data_type === 'json'
40
+ && schema[i].field_metadata.rich_text_type
41
+ && schema[i].field_metadata.embed_entry
42
+ && schema[i].reference_to.length > 1) {
43
+ flag.supressed = true;
44
+ schema[i].reference_to = ["sys_assets"]
45
+ }
39
46
  }
40
47
  };
@@ -6,7 +6,7 @@
6
6
 
7
7
  var supress = module.exports = function (schema, flag) {
8
8
  for (var i in schema) {
9
- if (schema[i].data_type === 'group') {
9
+ if (schema[i].data_type === 'group' || schema[i].data_type === 'global_field') {
10
10
  supress(schema[i].schema, flag);
11
11
  } else if (schema[i].data_type === 'blocks') {
12
12
  for (var block in schema[i].blocks) {
@@ -14,6 +14,10 @@ var supress = module.exports = function (schema, flag) {
14
14
  }
15
15
  } else if (schema[i].data_type === 'reference') {
16
16
  flag.references = true;
17
+ } else if (schema[i].data_type === 'json' && schema[i].field_metadata.rich_text_type) {
18
+ flag.jsonRte = true
19
+ if (schema[i].field_metadata.embed_entry === true)
20
+ flag.jsonRteEmbeddedEntries = true;
17
21
  }
18
22
 
19
23
  if ((schema[i].hasOwnProperty('mandatory') && schema[i].mandatory) || (schema[i].hasOwnProperty('unique') &&