mcdev 5.1.0 → 5.2.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 (192) hide show
  1. package/.eslintrc.json +4 -4
  2. package/.github/ISSUE_TEMPLATE/bug.yml +1 -0
  3. package/.github/PULL_REQUEST_TEMPLATE.md +2 -2
  4. package/.github/workflows/coverage-develop-branch.yml +0 -2
  5. package/.github/workflows/coverage-main-branch.yml +0 -2
  6. package/.github/workflows/coverage.yml +0 -2
  7. package/.husky/post-checkout +1 -0
  8. package/.husky/post-merge +1 -0
  9. package/.vscode/extensions.json +4 -0
  10. package/docs/dist/documentation.md +633 -286
  11. package/lib/Deployer.js +25 -25
  12. package/lib/MetadataTypeDefinitions.js +1 -1
  13. package/lib/MetadataTypeInfo.js +1 -1
  14. package/lib/Retriever.js +1 -1
  15. package/lib/cli.js +159 -9
  16. package/lib/index.js +395 -95
  17. package/lib/metadataTypes/Asset.js +10 -11
  18. package/lib/metadataTypes/AttributeGroup.js +76 -2
  19. package/lib/metadataTypes/AttributeSet.js +260 -0
  20. package/lib/metadataTypes/Automation.js +413 -96
  21. package/lib/metadataTypes/DataExtension.js +2 -2
  22. package/lib/metadataTypes/DataExtensionField.js +1 -1
  23. package/lib/metadataTypes/Event.js +2 -3
  24. package/lib/metadataTypes/Folder.js +1 -1
  25. package/lib/metadataTypes/Journey.js +5 -6
  26. package/lib/metadataTypes/MetadataType.js +149 -49
  27. package/lib/metadataTypes/MobileKeyword.js +8 -8
  28. package/lib/metadataTypes/MobileMessage.js +5 -5
  29. package/lib/metadataTypes/Query.js +26 -10
  30. package/lib/metadataTypes/Script.js +3 -3
  31. package/lib/metadataTypes/TransactionalSMS.js +5 -5
  32. package/lib/metadataTypes/TriggeredSend.js +25 -50
  33. package/lib/metadataTypes/User.js +7 -4
  34. package/lib/metadataTypes/definitions/AttributeGroup.definition.js +117 -106
  35. package/lib/metadataTypes/definitions/{SetDefinition.definition.js → AttributeSet.definition.js} +54 -27
  36. package/lib/metadataTypes/definitions/Automation.definition.js +22 -15
  37. package/lib/metadataTypes/definitions/ImportFile.definition.js +36 -6
  38. package/lib/metadataTypes/definitions/TriggeredSend.definition.js +1 -0
  39. package/lib/util/cache.js +9 -4
  40. package/lib/util/cli.js +40 -0
  41. package/lib/util/file.js +2 -2
  42. package/lib/util/init.js +84 -0
  43. package/lib/util/util.js +121 -13
  44. package/package.json +11 -11
  45. package/test/mockRoot/.mcdevrc.json +1 -1
  46. package/test/mockRoot/deploy/testInstance/testBU/automation/testExisting_automation.automation-meta.json +1 -2
  47. package/test/mockRoot/deploy/testInstance/testBU/automation/testNew_automation.automation-meta.json +5 -6
  48. package/test/mockRoot/deploy/testInstance/testBU/dataExtract/testExisting_dataExtract.dataExtract-meta.json +35 -0
  49. package/test/mockRoot/deploy/testInstance/testBU/dataExtract/testNew_dataExtract.dataExtract-meta.json +35 -0
  50. package/test/mockRoot/deploy/testInstance/testBU/fileTransfer/testExisting_fileTransfer.fileTransfer-meta.json +17 -0
  51. package/test/mockRoot/deploy/testInstance/testBU/fileTransfer/testNew_fileTransfer.fileTransfer-meta.json +17 -0
  52. package/test/mockRoot/deploy/testInstance/testBU/importFile/testExisting_importFile.importFile-meta.json +29 -0
  53. package/test/mockRoot/deploy/testInstance/testBU/importFile/testNew_importFile.importFile-meta.json +29 -0
  54. package/test/mockRoot/deploy/testInstance/testBU/query/testExisting_query_fixKeys.query-meta.json +11 -0
  55. package/test/mockRoot/deploy/testInstance/testBU/query/testExisting_query_fixKeys.query-meta.sql +6 -0
  56. package/test/mockRoot/deploy/testInstance/testBU/script/testExisting_script.script-meta.json +6 -0
  57. package/test/mockRoot/deploy/testInstance/testBU/script/testExisting_script.script-meta.ssjs +1 -0
  58. package/test/mockRoot/deploy/testInstance/testBU/script/testNew_script.script-meta.json +6 -0
  59. package/test/mockRoot/deploy/testInstance/testBU/script/testNew_script.script-meta.ssjs +1 -0
  60. package/test/mockRoot/deploy/testInstance/testBU/triggeredSend/testExisting_triggeredSend.triggeredSend-meta.json +29 -0
  61. package/test/mockRoot/deploy/testInstance/testBU/triggeredSend/testNew_triggeredSend.triggeredSend-meta.json +29 -0
  62. package/test/resourceFactory.js +77 -12
  63. package/test/resources/1111111/accountUser/retrieve-ActiveFlag=falseANDCustomerKey=testExisting_userANDEmaillike@-response.xml +27 -0
  64. package/test/resources/1111111/accountUser/retrieve-ActiveFlag=falseANDEmaillike@-response.xml +156 -0
  65. package/test/resources/1111111/accountUser/retrieve-ActiveFlag=trueANDEmailisNullORNamelikeapp userANDMustChangePassword=false-response.xml +87 -0
  66. package/test/resources/1111111/accountUser/retrieve-ActiveFlag=trueANDEmaillike@-response.xml +156 -0
  67. package/test/resources/1111111/accountUser/retrieve-CustomerKey=testExisting_userANDActiveFlag=trueANDEmailisNullORNamelikeapp userANDMustChangePassword=false-response.xml +27 -0
  68. package/test/resources/1111111/accountUserAccount/retrieve-AccountUser.AccountUserID=700301950-response.xml +60 -0
  69. package/test/resources/1111111/user/retrieve-expected.md +4 -2
  70. package/test/resources/9999999/attributeGroup/retrieve-expected.json +25 -0
  71. package/test/resources/9999999/attributeSet/retrieve-expected.json +748 -0
  72. package/test/resources/9999999/automation/build-expected.json +1 -2
  73. package/test/resources/9999999/automation/create-expected.json +7 -8
  74. package/test/resources/9999999/automation/create-testNew_automation-expected.md +4 -4
  75. package/test/resources/9999999/automation/patch_fixKeys-pause-expected.json +44 -0
  76. package/test/resources/9999999/automation/patch_fixKeys-schedule-expected.json +44 -0
  77. package/test/resources/9999999/automation/perform-08afb0e2-b00a-4c88-ad2e-1f7f8788c560-response.xml +42 -0
  78. package/test/resources/9999999/automation/perform-08afb0e2-b00a-4c88-fixKey_pause-response.xml +42 -0
  79. package/test/resources/9999999/automation/perform-08afb0e2-b00a-4c88-fixKey_schedule-response.xml +42 -0
  80. package/test/resources/9999999/automation/perform-a8afb0e2-b00a-4c88-ad2e-1f7f8788c560-response.xml +42 -0
  81. package/test/resources/9999999/automation/retrieve-expected.json +1 -2
  82. package/test/resources/9999999/automation/retrieve-testExisting_automation-expected.md +2 -2
  83. package/test/resources/9999999/automation/schedule-08afb0e2-b00a-4c88-ad2e-1f7f8788c560-response.xml +52 -0
  84. package/test/resources/9999999/automation/schedule-08afb0e2-b00a-4c88-ad2e-pause-response.xml +38 -0
  85. package/test/resources/9999999/automation/schedule-08afb0e2-b00a-4c88-fixKey_pause-response.xml +52 -0
  86. package/test/resources/9999999/automation/schedule-08afb0e2-b00a-4c88-fixKey_schedule-response.xml +52 -0
  87. package/test/resources/9999999/automation/schedule-a8afb0e2-b00a-4c88-ad2e-1f7f8788c560-response.xml +52 -0
  88. package/test/resources/9999999/automation/template-expected.json +1 -2
  89. package/test/resources/9999999/automation/update-expected.json +1 -2
  90. package/test/resources/9999999/automation/update-testExisting_automation-expected.md +2 -2
  91. package/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-ad2e-pause/get-response.json +85 -0
  92. package/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-ad2e-pause/patch-response.json +85 -0
  93. package/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-fixKey_pause/get-response.json +85 -0
  94. package/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-fixKey_pause/patch-response.json +85 -0
  95. package/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-fixKey_schedule/get-response.json +85 -0
  96. package/test/resources/9999999/automation/v1/automations/08afb0e2-b00a-4c88-fixKey_schedule/patch-response.json +85 -0
  97. package/test/resources/9999999/automation/v1/automations/a8afb0e2-b00a-4c88-ad2e-1f7f8788c560/get-response.json +1 -1
  98. package/test/resources/9999999/automation/v1/automations/post-response.json +20 -19
  99. package/test/resources/9999999/automation/v1/dataextracts/56c5370a-f988-4f36-b0ee-0f876573f6d7/patch-response.json +38 -0
  100. package/test/resources/9999999/automation/v1/dataextracts/post-response.json +38 -0
  101. package/test/resources/9999999/automation/v1/dataextracttypes/get-response.json +50 -0
  102. package/test/resources/9999999/automation/v1/filetransfers/72c328ac-f5b0-4e37-91d3-a775666f15a6/patch-response.json +18 -0
  103. package/test/resources/9999999/automation/v1/filetransfers/post-response.json +18 -0
  104. package/test/resources/9999999/automation/v1/ftplocations/get-response.json +18 -0
  105. package/test/resources/9999999/automation/v1/imports/9d16f42c-2260-ed11-b849-48df37d1de8b/patch-response.json +31 -0
  106. package/test/resources/9999999/automation/v1/imports/get-response.json +1 -1
  107. package/test/resources/9999999/automation/v1/imports/post-response.json +30 -0
  108. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dae/actions/start/post-response.txt +1 -0
  109. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat_fixKeys/get-response.json +17 -0
  110. package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat_fixKeys/patch-response.json +18 -0
  111. package/test/resources/9999999/automation/v1/queries/get-response.json +18 -1
  112. package/test/resources/9999999/automation/v1/scripts/39f6a488-20eb-4ba0-b0b9-023725b574e4/patch-response.json +10 -0
  113. package/test/resources/9999999/automation/v1/scripts/get-response.json +12 -2
  114. package/test/resources/9999999/automation/v1/scripts/post-response.json +10 -0
  115. package/test/resources/9999999/dataExtension/retrieve-Name=testExisting_dataExtension-response.xml +52 -0
  116. package/test/resources/9999999/dataExtensionField/retrieve-DataExtension.CustomerKey=testExisting_dataExtension-response.xml +98 -0
  117. package/test/resources/9999999/dataExtensionField/retrieve-DataExtension.CustomerKey=testNew_dataExtensionORDataExtension.CustomerKey=testExisting_dataExtension-response.xml +99 -0
  118. package/test/resources/9999999/dataExtract/build-expected.json +35 -0
  119. package/test/resources/9999999/dataExtract/get-expected.json +39 -0
  120. package/test/resources/9999999/dataExtract/patch-expected.json +37 -0
  121. package/test/resources/9999999/dataExtract/post-expected.json +37 -0
  122. package/test/resources/9999999/dataExtract/template-expected.json +35 -0
  123. package/test/resources/9999999/dataFolder/retrieve-ContentType=contextual_suppression_listORContentType=publicationORContentType=suppression_listORContentType=mysubsORContentType=list-response.xml +136 -0
  124. package/test/resources/9999999/dataFolder/retrieve-ContentType=ssjsactivity-response.xml +48 -0
  125. package/test/resources/9999999/dataFolder/retrieve-ContentType=triggered_send_journeybuilderORContentType=triggered_sendORContentType=hidden-response.xml +276 -0
  126. package/test/resources/9999999/dataFolder/retrieve-response.xml +23 -0
  127. package/test/resources/9999999/email/retrieve-response.xml +203 -0
  128. package/test/resources/9999999/fileTransfer/build-expected.json +15 -0
  129. package/test/resources/9999999/fileTransfer/get-expected.json +17 -0
  130. package/test/resources/9999999/fileTransfer/patch-expected.json +17 -0
  131. package/test/resources/9999999/fileTransfer/post-expected.json +17 -0
  132. package/test/resources/9999999/fileTransfer/template-expected.json +15 -0
  133. package/test/resources/9999999/hub/v1/contacts/schema/attributeGroups/get-response.json +585 -0
  134. package/test/resources/9999999/hub/v1/contacts/schema/setDefinitions/get-response.json +19807 -0
  135. package/test/resources/9999999/importFile/build-expected.json +27 -0
  136. package/test/resources/9999999/importFile/get-expected.json +29 -0
  137. package/test/resources/9999999/importFile/patch-expected.json +29 -0
  138. package/test/resources/9999999/importFile/post-expected.json +29 -0
  139. package/test/resources/9999999/importFile/template-expected.json +27 -0
  140. package/test/resources/9999999/program/retrieve-CustomerKey=testExisting_automation_fixKey_pause-response.xml +32 -0
  141. package/test/resources/9999999/program/retrieve-CustomerKey=testExisting_automation_fixKey_schedule-response.xml +32 -0
  142. package/test/resources/9999999/program/retrieve-CustomerKey=testExisting_automation_fixedKey_paused-response.xml +32 -0
  143. package/test/resources/9999999/program/retrieve-CustomerKey=testExisting_automation_fixedKey_scheduled-response.xml +32 -0
  144. package/test/resources/9999999/program/retrieve-CustomerKey=testExisting_automation_pause-response.xml +30 -0
  145. package/test/resources/9999999/program/retrieve-response.xml +21 -3
  146. package/test/resources/9999999/query/patch_fixKeys-expected.json +11 -0
  147. package/test/resources/9999999/query/patch_fixKeys-expected.sql +6 -0
  148. package/test/resources/9999999/queryDefinition/retrieve-CustomerKey=testExisting_query_fixKeysANDStatus=Active-response.xml +30 -0
  149. package/test/resources/9999999/queryDefinition/retrieve-CustomerKey=testExisting_query_fixedKeysANDStatus=Active-response.xml +30 -0
  150. package/test/resources/9999999/queryDefinition/retrieve-CustomerKey=testNew_queryANDStatus=Active-response.xml +30 -0
  151. package/test/resources/9999999/script/build-expected.json +6 -0
  152. package/test/resources/9999999/script/build-expected.ssjs +1 -0
  153. package/test/resources/9999999/script/get-expected.json +8 -0
  154. package/test/resources/9999999/script/get-expected.ssjs +1 -0
  155. package/test/resources/9999999/script/get_noScriptTag-expected.html +1 -0
  156. package/test/resources/9999999/script/get_noScriptTag-expected.json +8 -0
  157. package/test/resources/9999999/script/patch-expected.json +8 -0
  158. package/test/resources/9999999/script/patch-expected.ssjs +1 -0
  159. package/test/resources/9999999/script/post-expected.json +8 -0
  160. package/test/resources/9999999/script/post-expected.ssjs +1 -0
  161. package/test/resources/9999999/script/template-expected.json +6 -0
  162. package/test/resources/9999999/script/template-expected.ssjs +1 -0
  163. package/test/resources/9999999/triggeredSend/build-expected.json +29 -0
  164. package/test/resources/9999999/triggeredSend/get-expected.json +29 -0
  165. package/test/resources/9999999/triggeredSend/patch-expected.json +29 -0
  166. package/test/resources/9999999/triggeredSend/post-expected.json +29 -0
  167. package/test/resources/9999999/triggeredSend/template-expected.json +29 -0
  168. package/test/resources/9999999/triggeredSendDefinition/create-response.xml +75 -0
  169. package/test/resources/9999999/triggeredSendDefinition/delete-response.xml +36 -0
  170. package/test/resources/9999999/triggeredSendDefinition/{retrieve-response.xml → retrieve-TriggeredSendStatusINNew,Active,Inactive,Moved,Canceled-response.xml} +4 -4
  171. package/test/resources/9999999/triggeredSendDefinition/update-response.xml +74 -0
  172. package/test/type.attributeGroup.test.js +55 -0
  173. package/test/type.attributeSet.test.js +55 -0
  174. package/test/type.automation.test.js +638 -11
  175. package/test/type.dataExtension.test.js +0 -1
  176. package/test/type.dataExtract.test.js +187 -0
  177. package/test/type.fileTransfer.test.js +185 -0
  178. package/test/type.importFile.test.js +186 -0
  179. package/test/type.mobileKeyword.test.js +0 -1
  180. package/test/type.query.test.js +464 -13
  181. package/test/type.script.test.js +367 -0
  182. package/test/type.triggeredSend.test.js +152 -0
  183. package/test/type.user.test.js +22 -10
  184. package/test/utils.js +4 -1
  185. package/lib/metadataTypes/SetDefinition.js +0 -37
  186. /package/test/resources/1111111/accountUser/{retrieve-response.xml → retrieve-ActiveFlag=trueANDCustomerKey=testExisting_userANDEmaillike@-response.xml} +0 -0
  187. /package/test/resources/1111111/accountUserAccount/{retrieve-response.xml → retrieve-AccountUser.AccountUserIDIN700301950,700301951,7471228-response.xml} +0 -0
  188. /package/test/resources/1111111/businessUnit/{retrieve-response.xml → retrieve-ID=1111111-response.xml} +0 -0
  189. /package/test/resources/1111111/list/{retrieve-response.xml → retrieve-CustomerKey=All SubscribersORListName=All Subscribers-response.xml} +0 -0
  190. /package/test/resources/1111111/role/{retrieve-response.xml → retrieve-IsPrivate=false-response.xml} +0 -0
  191. /package/test/resources/9999999/emailSendDefinition/{retrieve-response.xml → retrieve-IsPlatformObject=falseANDDescriptionnotEqualsSFSendDefinition-response.xml} +0 -0
  192. /package/test/resources/9999999/queryDefinition/{retrieve-response.xml → retrieve-CustomerKey=testExisting_queryANDStatus=Active-response.xml} +0 -0
@@ -86,7 +86,7 @@ class Asset extends MetadataType {
86
86
  return { metadata: Object.values(metadata)[0], type: this.definition.type };
87
87
  }
88
88
  /**
89
- * helper for {@link retrieve} + {@link retrieveAsTemplate}
89
+ * helper for {@link Asset.retrieve} + {@link Asset.retrieveAsTemplate}
90
90
  *
91
91
  * @private
92
92
  * @returns {TYPE.AssetSubType[]} subtype array
@@ -448,14 +448,14 @@ class Asset extends MetadataType {
448
448
  );
449
449
  }
450
450
  /**
451
- * helper for {@link preDeployTasks}
451
+ * helper for {@link Asset.preDeployTasks}
452
452
  * Some metadata types store their actual content as a separate file, e.g. images
453
453
  * This method reads these from the local FS stores them in the metadata object allowing to deploy it
454
454
  *
455
455
  * @param {TYPE.AssetItem} metadata a single asset
456
456
  * @param {TYPE.AssetSubType} subType group of similar assets to put in a folder (ie. images)
457
457
  * @param {string} deployDir directory of deploy files
458
- * @param {boolean} [pathOnly=false] used by getFilesToCommit which does not need the binary file to be actually read
458
+ * @param {boolean} [pathOnly] used by getFilesToCommit which does not need the binary file to be actually read
459
459
  * @returns {Promise.<string>} if found will return the path of the binary file
460
460
  */
461
461
  static async _readExtendedFileFromFS(metadata, subType, deployDir, pathOnly = false) {
@@ -504,11 +504,10 @@ class Asset extends MetadataType {
504
504
  * @param {TYPE.MetadataTypeMap} metadata metadata mapped by their keyField
505
505
  * @param {TYPE.MetadataTypeMap} _ originalMetadata to be updated (contains additioanl fields)
506
506
  * @param {{created: number, updated: number}} createdUpdated counter representing successful creates/updates
507
- * @param {boolean} [isRefresh] optional flag to indicate that triggeredSend should be refreshed after deployment of assets
508
507
  * @returns {Promise.<void>} -
509
508
  */
510
- static async postDeployTasks(metadata, _, createdUpdated, isRefresh) {
511
- if (isRefresh) {
509
+ static async postDeployTasks(metadata, _, createdUpdated) {
510
+ if (Util.OPTIONS.refresh) {
512
511
  if (createdUpdated.updated) {
513
512
  // only run this if assets were updated. for created assets we do not expect
514
513
  this._refreshTriggeredSend(metadata);
@@ -521,7 +520,7 @@ class Asset extends MetadataType {
521
520
  }
522
521
 
523
522
  /**
524
- * helper for {@link postDeployTasks}. triggers a refresh of active triggerredSendDefinitions associated with the updated asset-message items. Gets executed if isRefresh is true.
523
+ * helper for {@link Asset.postDeployTasks}. triggers a refresh of active triggerredSendDefinitions associated with the updated asset-message items. Gets executed if refresh option has been set.
525
524
  *
526
525
  * @private
527
526
  * @param {TYPE.MetadataTypeMap} metadata metadata mapped by their keyField
@@ -546,7 +545,7 @@ class Asset extends MetadataType {
546
545
  TriggeredSend.client = this.client;
547
546
  try {
548
547
  // find refreshable TSDs
549
- const tsdObj = (await TriggeredSend.findRefreshableItems()).metadata;
548
+ const tsdObj = (await TriggeredSend.findRefreshableItems(true)).metadata;
550
549
 
551
550
  const tsdCountInitial = Object.keys(tsdObj).length;
552
551
  const emailCount = legacyIdArr.length;
@@ -867,7 +866,7 @@ class Asset extends MetadataType {
867
866
  }
868
867
 
869
868
  /**
870
- * helper for {@link preDeployTasks} that loads extracted code content back into JSON
869
+ * helper for {@link Asset.preDeployTasks} that loads extracted code content back into JSON
871
870
  *
872
871
  * @param {TYPE.AssetItem} metadata a single asset definition
873
872
  * @param {string} deployDir directory of deploy files
@@ -1151,7 +1150,7 @@ class Asset extends MetadataType {
1151
1150
  return fileList;
1152
1151
  }
1153
1152
  /**
1154
- * helper for {@link preDeployTasks} that loads extracted code content back into JSON
1153
+ * helper for {@link Asset.preDeployTasks} that loads extracted code content back into JSON
1155
1154
  *
1156
1155
  * @param {string} prefix usually the customerkey
1157
1156
  * @param {object} metadataSlots metadata.views.html.slots or deeper slots.<>.blocks.<>.slots
@@ -1231,7 +1230,7 @@ class Asset extends MetadataType {
1231
1230
  }
1232
1231
  }
1233
1232
  /**
1234
- * helper for {@link postRetrieveTasks} that finds code content in JSON and extracts it
1233
+ * helper for {@link Asset.postRetrieveTasks} that finds code content in JSON and extracts it
1235
1234
  * to allow saving that separately and formatted
1236
1235
  *
1237
1236
  * @param {TYPE.AssetItem} metadata a single asset definition
@@ -1,7 +1,9 @@
1
1
  'use strict';
2
2
 
3
- const MetadataType = require('./MetadataType');
4
3
  const TYPE = require('../../types/mcdev.d');
4
+ const MetadataType = require('./MetadataType');
5
+ const Util = require('../util/util');
6
+ const cache = require('../util/cache');
5
7
 
6
8
  /**
7
9
  * AttributeGroup MetadataType
@@ -18,7 +20,7 @@ class AttributeGroup extends MetadataType {
18
20
  * @param {string} [key] customer key of single item to retrieve
19
21
  * @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise of metadata
20
22
  */
21
- static retrieve(retrieveDir, _, __, key) {
23
+ static async retrieve(retrieveDir, _, __, key) {
22
24
  return super.retrieveREST(
23
25
  retrieveDir,
24
26
  '/hub/v1/contacts/schema/attributeGroups',
@@ -34,6 +36,78 @@ class AttributeGroup extends MetadataType {
34
36
  static retrieveForCache() {
35
37
  return super.retrieveREST(null, '/hub/v1/contacts/schema/attributeGroups');
36
38
  }
39
+
40
+ /**
41
+ * manages post retrieve steps
42
+ *
43
+ * @param {TYPE.MetadataTypeItem} metadata a single metadata
44
+ * @returns {TYPE.MetadataTypeItem} metadata
45
+ */
46
+ static postRetrieveTasks(metadata) {
47
+ // Member ID
48
+ delete metadata.mID;
49
+
50
+ // attributeSet
51
+ metadata.attributeSetIdentifiers = metadata.attributeSetIdentifiers.map((attributeSet) => {
52
+ try {
53
+ const key = cache.searchForField(
54
+ 'attributeSet',
55
+ attributeSet.definitionID,
56
+ 'definitionID',
57
+ 'definitionKey'
58
+ );
59
+ if (key !== attributeSet.definitionKey) {
60
+ throw new Error(
61
+ `AttributeSet key mismatch. Found ${key} instead of ${attributeSet.definitionKey}`
62
+ );
63
+ }
64
+ return key;
65
+ } catch (ex) {
66
+ Util.logger.warn(
67
+ ` - ${this.definition.type} ${metadata[this.definition.keyField]} (for ${
68
+ attributeSet.definitionKey
69
+ }): ${ex.message}`
70
+ );
71
+ return attributeSet;
72
+ }
73
+ });
74
+
75
+ // requiredRelationships
76
+ // TODO: implement
77
+
78
+ // description is not returned by API when empty. Set to empty string to propose the field as an option to users
79
+ metadata.description ||= '';
80
+
81
+ // applicationKey is only used by system generated attribute groups and otherwise it's empty.
82
+ if (metadata.applicationKey === '') {
83
+ // remove useless field
84
+ delete metadata.applicationKey;
85
+ }
86
+
87
+ // connectingID.identifierType seems to be always set to 'FullyQualifiedName' - to be sure we check it here and remove it if it's the case
88
+ if (metadata.connectingID?.identifierType === 'FullyQualifiedName') {
89
+ // remove useless field
90
+ delete metadata.connectingID;
91
+ }
92
+
93
+ // containsSchemaAttributes is only true for system generated attribute groups and otherwise it's false.
94
+ if (!metadata.containsSchemaAttributes) {
95
+ delete metadata.containsSchemaAttributes;
96
+ }
97
+
98
+ // isSystemDefined is only true for system generated attribute groups and cannot be deployed
99
+ if (!metadata.isSystemDefined) {
100
+ delete metadata.isSystemDefined;
101
+ }
102
+
103
+ return metadata;
104
+ }
105
+ /**
106
+ * prepares for deployment
107
+ *
108
+ * @param {TYPE.MetadataTypeItem} metadata a single item
109
+ * @returns {TYPE.MetadataTypeItem} Promise
110
+ */
37
111
  }
38
112
 
39
113
  // Assign definition to static attributes
@@ -0,0 +1,260 @@
1
+ 'use strict';
2
+
3
+ const TYPE = require('../../types/mcdev.d');
4
+ const MetadataType = require('./MetadataType');
5
+ const AttributeGroup = require('./AttributeGroup');
6
+ const Util = require('../util/util');
7
+ const cache = require('../util/cache');
8
+
9
+ /**
10
+ * AttributeSet MetadataType
11
+ *
12
+ * @augments MetadataType
13
+ */
14
+ class AttributeSet extends MetadataType {
15
+ /**
16
+ * Retrieves Metadata of schema set Definitions.
17
+ *
18
+ * @param {string} retrieveDir Directory where retrieved metadata directory will be saved
19
+ * @param {void} [_] unused parameter
20
+ * @param {void} [__] unused parameter
21
+ * @param {string} [key] customer key of single item to retrieve
22
+ * @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise
23
+ */
24
+ static async retrieve(retrieveDir, _, __, key) {
25
+ if (retrieveDir && !cache.getCache()?.attributeGroup) {
26
+ // ! attributeGroup and attributeSet both link to each other. caching attributeGroup here "manually", assuming that it's quicker than the other way round
27
+ Util.logger.info(' - Caching dependent Metadata: attributeGroup');
28
+ AttributeGroup.buObject = this.buObject;
29
+ AttributeGroup.client = this.client;
30
+ AttributeGroup.properties = this.properties;
31
+ const result = await AttributeGroup.retrieveForCache();
32
+ cache.setMetadata('attributeGroup', result.metadata);
33
+ }
34
+ return super.retrieveREST(
35
+ retrieveDir,
36
+ '/hub/v1/contacts/schema/setDefinitions',
37
+ null,
38
+ null,
39
+ key
40
+ );
41
+ }
42
+ /**
43
+ * Retrieves Metadata of schema set definitions for caching.
44
+ *
45
+ * @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise
46
+ */
47
+ static retrieveForCache() {
48
+ return super.retrieveREST(null, '/hub/v1/contacts/schema/setDefinitions');
49
+ }
50
+
51
+ /**
52
+ * Builds map of metadata entries mapped to their keyfields
53
+ *
54
+ * @param {object} body json of response body
55
+ * @param {string|number} [singleRetrieve] key of single item to filter by
56
+ * @returns {TYPE.MetadataTypeMap} keyField => metadata map
57
+ */
58
+ static parseResponseBody(body, singleRetrieve) {
59
+ const metadataCache = super.parseResponseBody(body);
60
+
61
+ // make sure we add the entire list to cache before running postRetrieveTasks because of the self-references this type is using
62
+ // usually, the cache is only written into after all postRetrieveTasks have been run
63
+ cache.setMetadata(this.definition.type, metadataCache);
64
+
65
+ const metadataStructure = super.parseResponseBody(body, singleRetrieve);
66
+ return metadataStructure;
67
+ }
68
+
69
+ /**
70
+ * manages post retrieve steps
71
+ *
72
+ * @param {TYPE.MetadataTypeItem} metadata a single metadata
73
+ * @returns {TYPE.MetadataTypeItem} metadata
74
+ */
75
+ static postRetrieveTasks(metadata) {
76
+ // folder
77
+ if (metadata.storageLogicalType === 'DataExtension') {
78
+ // attributeSet created for Group Connect do not have a folder
79
+ super.setFolderPath(metadata);
80
+ }
81
+
82
+ // source
83
+ switch (metadata.storageLogicalType) {
84
+ case 'ExactTargetSchema': // synced / shared DEs
85
+ case 'DataExtension': {
86
+ // local DEs
87
+ try {
88
+ metadata.r__dataExtension_CustomerKey = cache.searchForField(
89
+ 'dataExtension',
90
+ metadata.storageReferenceID.value,
91
+ 'ObjectID',
92
+ 'CustomerKey'
93
+ );
94
+ // TODO: check if fields in metadata.sendAttributeStorageName exist in data extension --> error
95
+ // TODO: check if fields in data extension exist in metadata.sendAttributeStorageName --> warn
96
+
97
+ delete metadata.storageReferenceID;
98
+ delete metadata.storageName;
99
+ delete metadata.storageObjectInformation; // type ExactTargetSchema only
100
+ } catch (ex) {
101
+ Util.logger.warn(
102
+ ` - ${this.definition.type} ${metadata[this.definition.keyField]}: ${
103
+ ex.message
104
+ }`
105
+ );
106
+ }
107
+ break;
108
+ }
109
+ case 'MobileAttributes': {
110
+ // TODO: implement
111
+ // "storageName": "_MobileAddress",
112
+
113
+ break;
114
+ }
115
+ case 'EnterpriseAttributes': {
116
+ // TODO: implement
117
+ // "storageName": "_EnterpriseAttribute",
118
+
119
+ break;
120
+ }
121
+ case 'PushAttributes': {
122
+ // TODO: implement
123
+ // "storageName": "_PushAddress",
124
+
125
+ break;
126
+ }
127
+ }
128
+
129
+ // relationships to attributeGroups & AttributeSet
130
+ if (Array.isArray(metadata.relationships)) {
131
+ for (const relationship of metadata.relationships) {
132
+ for (const type of ['left', 'right']) {
133
+ if (
134
+ relationship[type + 'Item']?.connectingID?.identifierType ===
135
+ 'FullyQualifiedName'
136
+ ) {
137
+ delete relationship[type + 'Item'].connectingID;
138
+ }
139
+ let relationshipObj = null;
140
+ switch (relationship[type + 'Item'].relationshipType) {
141
+ case 'AttributeGroup': {
142
+ try {
143
+ relationship[type + 'Item'].r__attributeGroup_definitionKey =
144
+ cache.searchForField(
145
+ 'attributeGroup',
146
+ relationship[type + 'Item']?.identifier,
147
+ 'definitionID',
148
+ 'definitionKey'
149
+ );
150
+ delete relationship[type + 'Item']?.identifier;
151
+ } catch (ex) {
152
+ Util.logger.warn(
153
+ ` - ${this.definition.type} ${
154
+ metadata[this.definition.keyField]
155
+ }: ${ex.message}`
156
+ );
157
+ }
158
+ // get relationship fieldnames
159
+ relationshipObj = {
160
+ valueDefinitions: this._getSystemValueDefinitions(),
161
+ };
162
+ break;
163
+ }
164
+ case 'AttributeSet': {
165
+ try {
166
+ relationship[type + 'Item'].r__attributeSet_definitionKey =
167
+ cache.searchForField(
168
+ 'attributeSet',
169
+ relationship[type + 'Item']?.identifier,
170
+ 'definitionID',
171
+ 'definitionKey'
172
+ );
173
+ delete relationship[type + 'Item']?.identifier;
174
+
175
+ // get relationship fieldnames
176
+ // check if its a self-reference to metadata.valueDefinitions or if it's a reference to another attributeSet
177
+ relationshipObj =
178
+ relationship[type + 'Item'].r__attributeSet_definitionKey ===
179
+ metadata.definitionKey
180
+ ? metadata
181
+ : cache.getByKey(
182
+ 'attributeSet',
183
+ relationship[type + 'Item']
184
+ .r__attributeSet_definitionKey
185
+ );
186
+ } catch (ex) {
187
+ Util.logger.warn(
188
+ ` - ${this.definition.type} ${
189
+ metadata[this.definition.keyField]
190
+ }: ${ex.message}`
191
+ );
192
+ }
193
+ break;
194
+ }
195
+ }
196
+ try {
197
+ // get relationship fieldnames
198
+ // resolve field values
199
+ for (const attr of relationship.relationshipAttributes) {
200
+ const id = attr[type + 'AttributeID'];
201
+ const valueDefinition = relationshipObj.valueDefinitions.find(
202
+ (item) => item.valueDefinitionID === id
203
+ );
204
+ if (valueDefinition) {
205
+ attr['c__' + type + 'FullyQualifiedName'] =
206
+ valueDefinition.fullyQualifiedName;
207
+ delete attr[type + 'AttributeID'];
208
+ delete attr[type + 'ConnectingID'];
209
+ } else {
210
+ throw new Error(
211
+ `Could not find ${type}AttributeID ${id} of relationship ${relationship.relationshipID}`
212
+ );
213
+ }
214
+ }
215
+ } catch (ex) {
216
+ Util.logger.warn(
217
+ ` - ${this.definition.type} ${metadata[this.definition.nameField]} / ${
218
+ metadata[this.definition.keyField]
219
+ }: ${ex.message}`
220
+ );
221
+ }
222
+ }
223
+ }
224
+ }
225
+
226
+ // Member ID
227
+ delete metadata.customObjectOwnerMID;
228
+
229
+ // connectingID.identifierType seems to be always set to 'FullyQualifiedName' - to be sure we check it here and remove it if it's the case
230
+ if (metadata.connectingID?.identifierType === 'FullyQualifiedName') {
231
+ // remove useless field
232
+ delete metadata.connectingID;
233
+ }
234
+
235
+ return metadata;
236
+ }
237
+
238
+ /**
239
+ * helper for {@link AttributeSet.postRetrieveTasks}
240
+ *
241
+ * @returns {object[]} all system value definitions
242
+ */
243
+ static _getSystemValueDefinitions() {
244
+ if (!this.systemValueDefinitions) {
245
+ this.systemValueDefinitions = Object.values(cache.getCache()['attributeSet'])
246
+ .flatMap((item) => {
247
+ if (item.isSystemDefined) {
248
+ return item.valueDefinitions;
249
+ }
250
+ })
251
+ .filter(Boolean);
252
+ }
253
+ return this.systemValueDefinitions;
254
+ }
255
+ }
256
+
257
+ // Assign definition to static attributes
258
+ AttributeSet.definition = require('../MetadataTypeDefinitions').attributeSet;
259
+
260
+ module.exports = AttributeSet;