mcdev 4.3.4 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.coverage-comment-template.md +20 -0
- package/.coverage-comment-template.svelte +178 -0
- package/.eslintrc.json +2 -0
- package/.github/ISSUE_TEMPLATE/bug.yml +1 -0
- package/.github/workflows/code-test.yml +36 -0
- package/.github/workflows/coverage-base-update.yml +57 -0
- package/.github/workflows/coverage-develop-branch.yml +41 -0
- package/.github/workflows/coverage-main-branch.yml +41 -0
- package/.github/workflows/coverage.yml +77 -0
- package/.husky/post-checkout +1 -1
- package/.prettierrc +1 -1
- package/.vscode/extensions.json +0 -4
- package/boilerplate/config.json +1 -1
- package/boilerplate/files/.prettierrc +1 -1
- package/boilerplate/files/.vscode/extensions.json +1 -1
- package/boilerplate/forcedUpdates.json +4 -0
- package/docs/dist/documentation.md +1196 -430
- package/lib/Builder.js +6 -1
- package/lib/Deployer.js +30 -5
- package/lib/MetadataTypeDefinitions.js +8 -6
- package/lib/MetadataTypeInfo.js +8 -6
- package/lib/cli.js +54 -42
- package/lib/index.js +82 -8
- package/lib/metadataTypes/Asset.js +73 -1
- package/lib/metadataTypes/AttributeGroup.js +0 -1
- package/lib/metadataTypes/Automation.js +48 -5
- package/lib/metadataTypes/Campaign.js +20 -7
- package/lib/metadataTypes/ContentArea.js +1 -1
- package/lib/metadataTypes/DataExtension.js +221 -184
- package/lib/metadataTypes/DataExtensionField.js +12 -19
- package/lib/metadataTypes/DataExtensionTemplate.js +1 -1
- package/lib/metadataTypes/DataExtract.js +1 -1
- package/lib/metadataTypes/DataExtractType.js +1 -1
- package/lib/metadataTypes/Email.js +1 -1
- package/lib/metadataTypes/{EmailSendDefinition.js → EmailSend.js} +5 -5
- package/lib/metadataTypes/{EventDefinition.js → Event.js} +17 -35
- package/lib/metadataTypes/{FtpLocation.js → FileLocation.js} +2 -2
- package/lib/metadataTypes/FileTransfer.js +8 -7
- package/lib/metadataTypes/Filter.js +1 -1
- package/lib/metadataTypes/Folder.js +8 -3
- package/lib/metadataTypes/ImportFile.js +6 -6
- package/lib/metadataTypes/{Interaction.js → Journey.js} +311 -147
- package/lib/metadataTypes/List.js +2 -2
- package/lib/metadataTypes/MetadataType.js +318 -90
- package/lib/metadataTypes/MobileCode.js +0 -1
- package/lib/metadataTypes/MobileKeyword.js +336 -40
- package/lib/metadataTypes/MobileMessage.js +473 -0
- package/lib/metadataTypes/Query.js +114 -32
- package/lib/metadataTypes/Role.js +60 -21
- package/lib/metadataTypes/Script.js +2 -3
- package/lib/metadataTypes/SendClassification.js +40 -0
- package/lib/metadataTypes/SetDefinition.js +1 -7
- package/lib/metadataTypes/TransactionalEmail.js +2 -3
- package/lib/metadataTypes/TransactionalMessage.js +1 -2
- package/lib/metadataTypes/TransactionalSMS.js +8 -15
- package/lib/metadataTypes/{TriggeredSendDefinition.js → TriggeredSend.js} +35 -27
- package/lib/metadataTypes/User.js +1177 -0
- package/lib/metadataTypes/definitions/Asset.definition.js +1 -0
- package/lib/metadataTypes/definitions/AttributeGroup.definition.js +1 -0
- package/lib/metadataTypes/definitions/Automation.definition.js +3 -2
- package/lib/metadataTypes/definitions/Campaign.definition.js +79 -4
- package/lib/metadataTypes/definitions/ContentArea.definition.js +1 -0
- package/lib/metadataTypes/definitions/DataExtension.definition.js +2 -1
- package/lib/metadataTypes/definitions/DataExtensionField.definition.js +1 -0
- package/lib/metadataTypes/definitions/DataExtensionTemplate.definition.js +1 -0
- package/lib/metadataTypes/definitions/DataExtract.definition.js +1 -0
- package/lib/metadataTypes/definitions/DataExtractType.definition.js +1 -0
- package/lib/metadataTypes/definitions/Discovery.definition.js +1 -0
- package/lib/metadataTypes/definitions/Email.definition.js +1 -0
- package/lib/metadataTypes/definitions/{EmailSendDefinition.definition.js → EmailSend.definition.js} +4 -2
- package/lib/metadataTypes/definitions/{EventDefinition.definition.js → Event.definition.js} +2 -1
- package/lib/metadataTypes/definitions/{FtpLocation.definition.js → FileLocation.definition.js} +4 -3
- package/lib/metadataTypes/definitions/FileTransfer.definition.js +3 -2
- package/lib/metadataTypes/definitions/Filter.definition.js +1 -0
- package/lib/metadataTypes/definitions/Folder.definition.js +2 -0
- package/lib/metadataTypes/definitions/ImportFile.definition.js +4 -3
- package/lib/metadataTypes/definitions/{Interaction.definition.js → Journey.definition.js} +11 -2
- package/lib/metadataTypes/definitions/List.definition.js +1 -0
- package/lib/metadataTypes/definitions/MobileCode.definition.js +3 -1
- package/lib/metadataTypes/definitions/MobileKeyword.definition.js +27 -17
- package/lib/metadataTypes/definitions/MobileMessage.definition.js +743 -0
- package/lib/metadataTypes/definitions/Query.definition.js +3 -2
- package/lib/metadataTypes/definitions/Role.definition.js +5 -0
- package/lib/metadataTypes/definitions/Script.definition.js +1 -0
- package/lib/metadataTypes/definitions/SendClassification.definition.js +114 -0
- package/lib/metadataTypes/definitions/SetDefinition.definition.js +1 -0
- package/lib/metadataTypes/definitions/TransactionalEmail.definition.js +2 -1
- package/lib/metadataTypes/definitions/TransactionalPush.definition.js +1 -0
- package/lib/metadataTypes/definitions/TransactionalSMS.definition.js +1 -0
- package/lib/metadataTypes/definitions/{TriggeredSendDefinition.definition.js → TriggeredSend.definition.js} +5 -3
- package/lib/metadataTypes/definitions/User.definition.js +365 -0
- package/lib/retrieveChangelog.js +1 -2
- package/lib/util/auth.js +29 -9
- package/lib/util/businessUnit.js +3 -3
- package/lib/util/cli.js +55 -7
- package/lib/util/devops.js +6 -4
- package/lib/util/file.js +55 -13
- package/lib/util/init.config.js +1 -2
- package/lib/util/init.npm.js +3 -3
- package/lib/util/util.js +23 -14
- package/package.json +16 -15
- package/test/general.test.js +62 -0
- package/test/mockRoot/.mcdevrc.json +7 -5
- package/test/mockRoot/deploy/testInstance/_ParentBU_/user/testBlocked_user.user-meta.json +23 -0
- package/test/mockRoot/deploy/testInstance/_ParentBU_/user/testExisting_user.user-meta.json +31 -0
- package/test/mockRoot/deploy/testInstance/_ParentBU_/user/testNew_user.user-meta.json +27 -0
- package/test/mockRoot/deploy/testInstance/testBU/dataExtension/{childBU_dataextension_test.dataExtension-meta.json → testExisting_dataExtension.dataExtension-meta.json} +2 -2
- package/test/mockRoot/deploy/testInstance/testBU/dataExtension/{testDataExtension.dataExtension-meta.json → testNew_dataExtension.dataExtension-meta.json} +2 -2
- package/test/mockRoot/deploy/testInstance/testBU/journey/testExisting_interaction.interaction-meta.json +576 -0
- package/test/mockRoot/deploy/testInstance/testBU/mobileKeyword/testNew_keyword.mobileKeyword-meta.amp +2 -0
- package/test/mockRoot/deploy/testInstance/testBU/mobileKeyword/testNew_keyword.mobileKeyword-meta.json +10 -0
- package/test/mockRoot/deploy/testInstance/testBU/mobileKeyword/testNew_keyword_blocked.mobileKeyword-meta.amp +2 -0
- package/test/mockRoot/deploy/testInstance/testBU/mobileKeyword/testNew_keyword_blocked.mobileKeyword-meta.json +10 -0
- package/test/mockRoot/deploy/testInstance/testBU/mobileMessage/NTIzOjc4OjA.mobileMessage-meta.amp +1 -0
- package/test/mockRoot/deploy/testInstance/testBU/mobileMessage/NTIzOjc4OjA.mobileMessage-meta.json +61 -0
- package/test/mockRoot/deploy/testInstance/testBU/mobileMessage/new.mobileMessage-meta.amp +1 -0
- package/test/mockRoot/deploy/testInstance/testBU/mobileMessage/new.mobileMessage-meta.json +60 -0
- package/test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.json +1 -1
- package/test/mockRoot/deploy/testInstance/testBU/query/testNewQuery.query-meta.json +1 -1
- package/test/mockRoot/deploy/testInstance/testBU/query/testNewQuery.query-meta.sql +1 -1
- package/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testExisting_temail.transactionalEmail-meta.json +1 -1
- package/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testNew_temail.transactionalEmail-meta.json +1 -1
- package/test/resourceFactory.js +13 -0
- package/test/resources/1111111/accountUser/configure-response.xml +70 -0
- package/test/resources/1111111/accountUser/create-response.xml +97 -0
- package/test/resources/1111111/accountUser/retrieve-response.xml +156 -0
- package/test/resources/1111111/accountUser/update-response.xml +111 -0
- package/test/resources/1111111/accountUserAccount/retrieve-response.xml +77 -0
- package/test/resources/1111111/platform/v1/setup/quickflow/data/get-response.json +455 -0
- package/test/resources/1111111/role/retrieve-response.xml +76 -0
- package/test/resources/1111111/user/build-expected.json +16 -0
- package/test/resources/1111111/user/create-expected.json +21 -0
- package/test/resources/1111111/user/retrieve-expected.json +24 -0
- package/test/resources/1111111/user/template-expected.json +16 -0
- package/test/resources/1111111/user/update-expected.json +21 -0
- package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/delete-response.json +1 -0
- package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/get-response.json +17 -0
- package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/patch-response.json +3 -3
- package/test/resources/9999999/automation/v1/queries/get-response.json +21 -4
- package/test/resources/9999999/automation/v1/queries/post-response.json +4 -4
- package/test/resources/9999999/data/v1/customobjectdata/key/{childBU_dataextension_test → testExisting_dataExtension}/rowset/get-response.json +1 -1
- package/test/resources/9999999/dataExtension/build-expected.json +3 -3
- package/test/resources/9999999/dataExtension/create-expected.json +2 -2
- package/test/resources/9999999/dataExtension/create-response.xml +8 -3
- package/test/resources/9999999/dataExtension/retrieve-expected.json +3 -3
- package/test/resources/9999999/dataExtension/retrieve-response.xml +9 -4
- package/test/resources/9999999/dataExtension/template-expected.json +3 -3
- package/test/resources/9999999/dataExtension/update-expected.json +3 -3
- package/test/resources/9999999/dataExtension/update-response.xml +9 -4
- package/test/resources/9999999/dataExtensionField/retrieve-response.xml +14 -9
- package/test/resources/9999999/interaction/v1/interactions/get-response.json +312 -0
- package/test/resources/9999999/interaction/v1/interactions/key_testExisting_interaction/get-response.json +312 -0
- package/test/resources/9999999/interaction/v1/interactions/key_testExisting_interaction/put-response.json +592 -0
- package/test/resources/9999999/journey/build-expected.json +572 -0
- package/test/resources/9999999/journey/get-expected.json +576 -0
- package/test/resources/9999999/journey/put-expected.json +576 -0
- package/test/resources/9999999/journey/template-expected.json +572 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/keyword/NXV4ZFMwTEFwRVczd3RaLUF5X3p5dzo4Njow/get-response.json +42 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/keyword/cTVJaG5oSDJPVUNHcUh6Z3pQT2tVdzo4Njow/delete-response.json +0 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/keyword/get-response.json +1 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/keyword/post-response.json +3 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/message/NTIzOjc4OjA/delete-response.json +0 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/message/NTIzOjc4OjA/get-response.json +106 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/message/NTIzOjc4OjA/post-response.json +0 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/message/NTQ3Ojc4OjA/get-response.json +127 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/message/get-response.json +129 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/message/post-response.json +3 -0
- package/test/resources/9999999/legacy/v1/beta2/data/campaign/get-response.json +29 -0
- package/test/resources/9999999/messaging/v1/email/definitions/post-response.json +1 -1
- package/test/resources/9999999/messaging/v1/email/definitions/testExisting_temail/get-response.json +1 -1
- package/test/resources/9999999/messaging/v1/email/definitions/testExisting_temail/patch-response.json +1 -1
- package/test/resources/9999999/mobileKeyword/build-expected.amp +2 -0
- package/test/resources/9999999/mobileKeyword/build-expected.json +9 -0
- package/test/resources/9999999/mobileKeyword/get-expected.amp +2 -0
- package/test/resources/9999999/mobileKeyword/get-expected.json +15 -0
- package/test/resources/9999999/mobileKeyword/post-create-expected.amp +2 -0
- package/test/resources/9999999/mobileKeyword/post-create-expected.json +17 -0
- package/test/resources/9999999/mobileKeyword/template-expected.amp +2 -0
- package/test/resources/9999999/mobileKeyword/template-expected.json +9 -0
- package/test/resources/9999999/mobileMessage/build-expected.amp +1 -0
- package/test/resources/9999999/mobileMessage/build-expected.json +60 -0
- package/test/resources/9999999/mobileMessage/get-expected.amp +1 -0
- package/test/resources/9999999/mobileMessage/get-expected.json +61 -0
- package/test/resources/9999999/mobileMessage/post-create-expected.amp +1 -0
- package/test/resources/9999999/mobileMessage/post-create-expected.json +63 -0
- package/test/resources/9999999/mobileMessage/post-update-expected.amp +1 -0
- package/test/resources/9999999/mobileMessage/post-update-expected.json +61 -0
- package/test/resources/9999999/mobileMessage/template-expected.amp +1 -0
- package/test/resources/9999999/mobileMessage/template-expected.json +60 -0
- package/test/resources/9999999/query/build-expected.json +1 -1
- package/test/resources/9999999/query/get-expected.json +1 -1
- package/test/resources/9999999/query/get2-expected.json +11 -0
- package/test/resources/9999999/query/patch-expected.json +1 -1
- package/test/resources/9999999/query/post-expected.json +1 -1
- package/test/resources/9999999/query/template-expected.json +1 -1
- package/test/resources/9999999/queryDefinition/retrieve-response.xml +30 -0
- package/test/resources/9999999/transactionalEmail/build-expected.json +5 -5
- package/test/resources/9999999/transactionalEmail/get-expected.json +1 -1
- package/test/resources/9999999/transactionalEmail/patch-expected.json +1 -1
- package/test/resources/9999999/transactionalEmail/post-expected.json +1 -1
- package/test/resources/9999999/transactionalEmail/template-expected.json +5 -5
- package/test/resources/9999999/transactionalPush/build-expected.json +2 -2
- package/test/resources/9999999/transactionalPush/template-expected.json +2 -2
- package/test/resources/9999999/transactionalSMS/build-expected.json +3 -3
- package/test/resources/9999999/transactionalSMS/template-expected.json +3 -3
- package/test/{dataExtension.test.js → type.dataExtension.test.js} +78 -21
- package/test/{interaction.test.js → type.journey.test.js} +64 -30
- package/test/type.mobileKeyword.test.js +250 -0
- package/test/type.mobileMessage.test.js +205 -0
- package/test/{query.test.js → type.query.test.js} +102 -5
- package/test/{transactionalEmail.test.js → type.transactionalEmail.test.js} +40 -2
- package/test/{transactionalPush.test.js → type.transactionalPush.test.js} +41 -2
- package/test/{transactionalSMS.test.js → type.transactionalSMS.test.js} +73 -3
- package/test/type.user.test.js +160 -0
- package/test/utils.js +17 -5
- package/types/mcdev.d.js +48 -15
- package/.github/workflows/code-analysis.yml +0 -57
- package/lib/metadataTypes/AccountUser.js +0 -426
- package/lib/metadataTypes/definitions/AccountUser.definition.js +0 -227
- package/test/mockRoot/deploy/testInstance/testBU/interaction/testExisting_interaction.interaction-meta.json +0 -266
- package/test/resources/9999999/interaction/build-expected.json +0 -260
- package/test/resources/9999999/interaction/get-expected.json +0 -264
- package/test/resources/9999999/interaction/put-expected.json +0 -264
- package/test/resources/9999999/interaction/template-expected.json +0 -260
- package/test/resources/9999999/interaction/v1/interactions/put-response.json +0 -280
- /package/test/mockRoot/deploy/testInstance/testBU/{interaction → journey}/testNew_interaction.interaction-meta.json +0 -0
- /package/test/resources/9999999/{interaction → journey}/post-expected.json +0 -0
package/test/utils.js
CHANGED
|
@@ -17,10 +17,11 @@ const resourceFactory = require('./resourceFactory');
|
|
|
17
17
|
*
|
|
18
18
|
* @param {string} customerKey of metadata
|
|
19
19
|
* @param {string} type of metadata
|
|
20
|
+
* @param {string} [buName] used when we need to test on ParentBU
|
|
20
21
|
* @returns {Promise.<string>} file in string form
|
|
21
22
|
*/
|
|
22
|
-
exports.getActualJson = (customerKey, type) =>
|
|
23
|
-
File.readJSON(`./retrieve/testInstance
|
|
23
|
+
exports.getActualJson = (customerKey, type, buName = 'testBU') =>
|
|
24
|
+
File.readJSON(`./retrieve/testInstance/${buName}/${type}/${customerKey}.${type}-meta.json`);
|
|
24
25
|
/**
|
|
25
26
|
* gets file from Retrieve folder
|
|
26
27
|
*
|
|
@@ -36,10 +37,11 @@ exports.getActualFile = (customerKey, type, ext) =>
|
|
|
36
37
|
*
|
|
37
38
|
* @param {string} customerKey of metadata
|
|
38
39
|
* @param {string} type of metadata
|
|
40
|
+
* @param {string} [buName] used when we need to test on ParentBU
|
|
39
41
|
* @returns {Promise.<string>} file in string form
|
|
40
42
|
*/
|
|
41
|
-
exports.getActualDeployJson = (customerKey, type) =>
|
|
42
|
-
File.readJSON(`./deploy/testInstance
|
|
43
|
+
exports.getActualDeployJson = (customerKey, type, buName = 'testBU') =>
|
|
44
|
+
File.readJSON(`./deploy/testInstance/${buName}/${type}/${customerKey}.${type}-meta.json`);
|
|
43
45
|
/**
|
|
44
46
|
* gets file from Deploy folder
|
|
45
47
|
*
|
|
@@ -143,6 +145,9 @@ exports.mockSetup = (isDeploy) => {
|
|
|
143
145
|
fsMockConf.deploy = fsmock.load(path.resolve(__dirname, 'mockRoot/deploy'));
|
|
144
146
|
}
|
|
145
147
|
fsmock(fsMockConf);
|
|
148
|
+
|
|
149
|
+
// ! reset exitCode or else tests could influence each other; do this in mockSetup to to ensure correct starting value
|
|
150
|
+
process.exitCode = 0;
|
|
146
151
|
};
|
|
147
152
|
|
|
148
153
|
/**
|
|
@@ -151,6 +156,13 @@ exports.mockSetup = (isDeploy) => {
|
|
|
151
156
|
* @returns {void}
|
|
152
157
|
*/
|
|
153
158
|
exports.mockReset = () => {
|
|
159
|
+
// remove all options that might have been set by previous tests
|
|
160
|
+
for (const key in Util.OPTIONS) {
|
|
161
|
+
if (Object.prototype.hasOwnProperty.call(Util.OPTIONS, key)) {
|
|
162
|
+
delete Util.OPTIONS[key];
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// reset sfmc login
|
|
154
166
|
auth.clearSessions();
|
|
155
167
|
fsmock.restore();
|
|
156
168
|
apimock.restore();
|
|
@@ -202,5 +214,5 @@ exports.logAPIHistoryDebug = () => {
|
|
|
202
214
|
* @returns {string} escaped string
|
|
203
215
|
*/
|
|
204
216
|
function escapeRegExp(str) {
|
|
205
|
-
return str.
|
|
217
|
+
return str.replaceAll(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
|
|
206
218
|
}
|
package/types/mcdev.d.js
CHANGED
|
@@ -12,7 +12,7 @@ const SDK = require('sfmc-sdk');
|
|
|
12
12
|
*/
|
|
13
13
|
/**
|
|
14
14
|
* @typedef {Object.<string, string>} TemplateMap
|
|
15
|
-
* @typedef {'accountUser'|'asset'|'asset-archive'|'asset-asset'|'asset-audio'|'asset-block'|'asset-code'|'asset-document'|'asset-image'|'asset-message'|'asset-other'|'asset-rawimage'|'asset-template'|'asset-textfile'|'asset-video'|'attributeGroup'|'automation'|'campaign'|'contentArea'|'dataExtension'|'dataExtensionField'|'dataExtensionTemplate'|'dataExtract'|'dataExtractType'|'discovery'|'email'|'
|
|
15
|
+
* @typedef {'accountUser'|'asset'|'asset-archive'|'asset-asset'|'asset-audio'|'asset-block'|'asset-code'|'asset-document'|'asset-image'|'asset-message'|'asset-other'|'asset-rawimage'|'asset-template'|'asset-textfile'|'asset-video'|'attributeGroup'|'automation'|'campaign'|'contentArea'|'dataExtension'|'dataExtensionField'|'dataExtensionTemplate'|'dataExtract'|'dataExtractType'|'discovery'|'email'|'emailSend'|'event'|'fileTransfer'|'filter'|'folder'|'fileLocation'|'importFile'|'interaction'|'list'|'mobileCode'|'mobileKeyword'|'query'|'role'|'script'|'setDefinition'|'triggeredSend'} SupportedMetadataTypes
|
|
16
16
|
* @typedef {Object.<SupportedMetadataTypes, string[]>} TypeKeyCombo object-key=metadata type, value=array of external keys
|
|
17
17
|
*/
|
|
18
18
|
|
|
@@ -21,10 +21,10 @@ const SDK = require('sfmc-sdk');
|
|
|
21
21
|
* @typedef {Object.<string, MetadataTypeItem>} MetadataTypeMap key=customer key
|
|
22
22
|
* @typedef {Object.<string, MetadataTypeMap>} MultiMetadataTypeMap key=Supported MetadataType
|
|
23
23
|
* @typedef {Object.<string, MetadataTypeItem[]>} MultiMetadataTypeList key=Supported MetadataType
|
|
24
|
-
* @typedef {{metadata:MetadataTypeMap,type:SupportedMetadataTypes}} MetadataTypeMapObj
|
|
25
|
-
* @typedef {{metadata:MetadataTypeItem,type:SupportedMetadataTypes}} MetadataTypeItemObj
|
|
24
|
+
* @typedef {{metadata: MetadataTypeMap, type: SupportedMetadataTypes}} MetadataTypeMapObj
|
|
25
|
+
* @typedef {{metadata: MetadataTypeItem, type: SupportedMetadataTypes}} MetadataTypeItemObj
|
|
26
26
|
* @typedef {Object.<number, MultiMetadataTypeMap>} Cache key=MID
|
|
27
|
-
* @typedef {{before:
|
|
27
|
+
* @typedef {{before: MetadataTypeItem, after: MetadataTypeItem}} MetadataTypeItemDiff used during update
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
30
|
/**
|
|
@@ -119,24 +119,57 @@ const SDK = require('sfmc-sdk');
|
|
|
119
119
|
* @typedef {Object.<string, DataExtensionItem>} DataExtensionMap
|
|
120
120
|
*/
|
|
121
121
|
/**
|
|
122
|
-
* @typedef {object}
|
|
123
|
-
* @property {string}
|
|
124
|
-
* @property {string} UserID
|
|
125
|
-
* @property {
|
|
122
|
+
* @typedef {object} UserDocument
|
|
123
|
+
* @property {string} [ID] equal to UserID; optional in update/create calls
|
|
124
|
+
* @property {string} UserID equal to ID; required in update/create calls
|
|
125
|
+
* @property {number} [AccountUserID] user.AccountUserID
|
|
126
|
+
* @property {number} c__AccountUserID copy of AccountUserID
|
|
126
127
|
* @property {string} CustomerKey user.CustomerKey
|
|
127
128
|
* @property {string} Name user.Name
|
|
128
129
|
* @property {string} Email user.Email
|
|
129
130
|
* @property {string} NotificationEmailAddress user.NotificationEmailAddress
|
|
130
|
-
* @property {
|
|
131
|
-
* @property {
|
|
132
|
-
* @property {
|
|
133
|
-
* @property {
|
|
134
|
-
* @property {
|
|
135
|
-
* @property {
|
|
136
|
-
* @property {
|
|
131
|
+
* @property {boolean} ActiveFlag user.ActiveFlag === true ? '✓' : '-'
|
|
132
|
+
* @property {boolean} IsAPIUser user.IsAPIUser === true ? '✓' : '-'
|
|
133
|
+
* @property {boolean} MustChangePassword user.MustChangePassword === true ? '✓' : '-'
|
|
134
|
+
* @property {number} DefaultBusinessUnit defaultBUName
|
|
135
|
+
* @property {number[]} c__AssociatedBusinessUnits associatedBus
|
|
136
|
+
* @property {object} [Roles] (API only)
|
|
137
|
+
* @property {object[]} [Roles.Role] roles (API only)
|
|
138
|
+
* @property {string[]} c__RoleNamesGlobal roles
|
|
139
|
+
* @property {string[]} UserPermissions userPermissions
|
|
137
140
|
* @property {string} LastSuccessfulLogin this.timeSinceDate(user.LastSuccessfulLogin)
|
|
138
141
|
* @property {string} CreatedDate user.CreatedDate
|
|
139
142
|
* @property {string} ModifiedDate user.ModifiedDate
|
|
143
|
+
* @property {object} Client -
|
|
144
|
+
* @property {number} [Client.ID] EID e.g:7281698
|
|
145
|
+
* @property {number} Client.ModifiedBy AccountUserID of user who last modified this user
|
|
146
|
+
* @property {'User'|'Installed Package'} c__type -
|
|
147
|
+
* @property {boolean} [IsLocked] (API only)
|
|
148
|
+
* @property {boolean} [Unlock] used to unlock a user that has IsLocked === true
|
|
149
|
+
* @property {boolean} c__IsLocked_readOnly copy of IsLocked
|
|
150
|
+
* @property {string} c__TimeZoneName name of timezone
|
|
151
|
+
* @property {object} [TimeZone] (API only)
|
|
152
|
+
* @property {string} [TimeZone.Name] (API only)
|
|
153
|
+
* @property {string} [TimeZone.ID] (API only)
|
|
154
|
+
* @property {'en-US'|'fr-CA'|'fr-FR'|'de-DE'|'it-IT'|'ja-JP'|'pt-BR'|'es-419'|'es-ES'} c__LocaleCode fr-CA, en-US, ...
|
|
155
|
+
* @property {object} [Locale] (API only)
|
|
156
|
+
* @property {'en-US'|'fr-CA'|'fr-FR'|'de-DE'|'it-IT'|'ja-JP'|'pt-BR'|'es-419'|'es-ES'} [Locale.LocaleCode] (API only)
|
|
157
|
+
* @typedef {{before:UserDocument,after:UserDocument}} UserDocumentDiff
|
|
158
|
+
* @typedef {Object.<string, UserDocument>} UserDocumentMap key=customer key
|
|
159
|
+
*/
|
|
160
|
+
/**
|
|
161
|
+
* @typedef {object} AccountUserConfiguration
|
|
162
|
+
* @property {object} Client wrapper
|
|
163
|
+
* @property {number} Client.ID EID e.g:7281698
|
|
164
|
+
* @property {string} [PartnerKey] empty string
|
|
165
|
+
* @property {number} ID User ID e.g:717133502
|
|
166
|
+
* @property {string} [ObjectID] empty string
|
|
167
|
+
* @property {number} [Delete] 0,1
|
|
168
|
+
* @property {BusinessUnitAssignmentConfiguration} BusinessUnitAssignmentConfiguration -
|
|
169
|
+
* @typedef {object} BusinessUnitAssignmentConfiguration
|
|
170
|
+
* @property {object} BusinessUnitIds wrapper
|
|
171
|
+
* @property {number[]|number} BusinessUnitIds.BusinessUnitId e.g:[518003624]
|
|
172
|
+
* @property {boolean} IsDelete assign BU if false, remove assignment if true
|
|
140
173
|
*/
|
|
141
174
|
|
|
142
175
|
/**
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# For most projects, this workflow file will not need changing; you simply need
|
|
2
|
-
# to commit it to your repository.
|
|
3
|
-
#
|
|
4
|
-
# You may wish to alter this file to override the set of languages analyzed,
|
|
5
|
-
# or to provide custom queries or build logic.
|
|
6
|
-
#
|
|
7
|
-
# ******** NOTE ********
|
|
8
|
-
# We have attempted to detect the languages in your repository. Please check
|
|
9
|
-
# the `language` matrix defined below to confirm you have the correct set of
|
|
10
|
-
# supported CodeQL languages.
|
|
11
|
-
#
|
|
12
|
-
name: 'CodeAnalysis'
|
|
13
|
-
|
|
14
|
-
on:
|
|
15
|
-
push:
|
|
16
|
-
branches: [main, develop, hotfix]
|
|
17
|
-
pull_request:
|
|
18
|
-
# The branches below must be a subset of the branches above
|
|
19
|
-
branches: [main, develop, hotfix]
|
|
20
|
-
|
|
21
|
-
jobs:
|
|
22
|
-
analyzeAndTest:
|
|
23
|
-
name: Analyze & Test
|
|
24
|
-
runs-on: ubuntu-latest
|
|
25
|
-
permissions:
|
|
26
|
-
actions: read
|
|
27
|
-
contents: read
|
|
28
|
-
security-events: write
|
|
29
|
-
|
|
30
|
-
strategy:
|
|
31
|
-
fail-fast: false
|
|
32
|
-
matrix:
|
|
33
|
-
language: ['javascript']
|
|
34
|
-
|
|
35
|
-
steps:
|
|
36
|
-
- name: Checkout repository
|
|
37
|
-
uses: actions/checkout@v3
|
|
38
|
-
|
|
39
|
-
- uses: actions/setup-node@v3
|
|
40
|
-
with:
|
|
41
|
-
node-version: 16
|
|
42
|
-
registry-url: https://registry.npmjs.org/
|
|
43
|
-
|
|
44
|
-
- run: npm ci --ignore-scripts
|
|
45
|
-
|
|
46
|
-
- run: npm run lint
|
|
47
|
-
|
|
48
|
-
# Initializes the CodeQL tools for scanning.
|
|
49
|
-
- name: Initialize CodeQL
|
|
50
|
-
uses: github/codeql-action/init@v2
|
|
51
|
-
with:
|
|
52
|
-
languages: ${{ matrix.language }}
|
|
53
|
-
- name: Perform CodeQL Analysis
|
|
54
|
-
uses: github/codeql-action/analyze@v2
|
|
55
|
-
|
|
56
|
-
# Assuming code passes, run tests
|
|
57
|
-
- run: npm run test
|
|
@@ -1,426 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const TYPE = require('../../types/mcdev.d');
|
|
4
|
-
const MetadataType = require('./MetadataType');
|
|
5
|
-
const Util = require('../util/util');
|
|
6
|
-
const File = require('../util/file');
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* MessageSendActivity MetadataType
|
|
10
|
-
*
|
|
11
|
-
* @augments MetadataType
|
|
12
|
-
*/
|
|
13
|
-
class AccountUser extends MetadataType {
|
|
14
|
-
/**
|
|
15
|
-
* Retrieves SOAP based metadata of metadata type into local filesystem. executes callback with retrieved metadata
|
|
16
|
-
*
|
|
17
|
-
* @param {string} retrieveDir Directory where retrieved metadata directory will be saved
|
|
18
|
-
* @param {void} _ unused parameter
|
|
19
|
-
* @param {void} [__] unused parameter
|
|
20
|
-
* @param {string} [key] customer key of single item to retrieve
|
|
21
|
-
* @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise of metadata
|
|
22
|
-
*/
|
|
23
|
-
static async retrieve(retrieveDir, _, __, key) {
|
|
24
|
-
if (this.buObject.eid !== this.buObject.mid) {
|
|
25
|
-
Util.logger.info(' - Skipping User retrieval on non-parent BU');
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
return this._retrieve(retrieveDir, key);
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Retrieves SOAP based metadata of metadata type into local filesystem. executes callback with retrieved metadata
|
|
32
|
-
*
|
|
33
|
-
* @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise of metadata
|
|
34
|
-
*/
|
|
35
|
-
static async retrieveChangelog() {
|
|
36
|
-
return this._retrieve();
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Retrieves SOAP based metadata of metadata type into local filesystem. executes callback with retrieved metadata
|
|
40
|
-
*
|
|
41
|
-
* @private
|
|
42
|
-
* @param {string} retrieveDir Directory where retrieved metadata directory will be saved
|
|
43
|
-
* @param {string} [key] customer key of single item to retrieve
|
|
44
|
-
* @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise of metadata
|
|
45
|
-
*/
|
|
46
|
-
static async _retrieve(retrieveDir, key) {
|
|
47
|
-
Util.logger.info(' - Caching dependent Metadata: AccountUserAccount');
|
|
48
|
-
|
|
49
|
-
// get BUs that each users have access to
|
|
50
|
-
const optionsBUs = {};
|
|
51
|
-
|
|
52
|
-
const resultsBatch = (
|
|
53
|
-
await this.client.soap.retrieveBulk(
|
|
54
|
-
'AccountUserAccount',
|
|
55
|
-
['AccountUser.AccountUserID', 'AccountUser.UserID', 'Account.ID', 'Account.Name'],
|
|
56
|
-
optionsBUs
|
|
57
|
-
)
|
|
58
|
-
).Results;
|
|
59
|
-
this.userIdBuMap = {};
|
|
60
|
-
for (const item of resultsBatch) {
|
|
61
|
-
this.userIdBuMap[item.AccountUser.AccountUserID] =
|
|
62
|
-
this.userIdBuMap[item.AccountUser.AccountUserID] || [];
|
|
63
|
-
// push to array if not already in array
|
|
64
|
-
if (
|
|
65
|
-
!this.userIdBuMap[item.AccountUser.AccountUserID].some(
|
|
66
|
-
(bu) => bu.ID === item.Account.ID
|
|
67
|
-
)
|
|
68
|
-
) {
|
|
69
|
-
this.userIdBuMap[item.AccountUser.AccountUserID].push({
|
|
70
|
-
ID: item.Account.ID,
|
|
71
|
-
Name: item.Account.Name,
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
// get actual user details
|
|
76
|
-
/** @type {TYPE.SoapRequestParams} */
|
|
77
|
-
let requestParams = {
|
|
78
|
-
QueryAllAccounts: true,
|
|
79
|
-
|
|
80
|
-
filter: {
|
|
81
|
-
leftOperand: {
|
|
82
|
-
// normal users
|
|
83
|
-
leftOperand: 'Email',
|
|
84
|
-
operator: 'like',
|
|
85
|
-
rightOperand: '@',
|
|
86
|
-
},
|
|
87
|
-
operator: 'OR',
|
|
88
|
-
rightOperand: {
|
|
89
|
-
// installed packages
|
|
90
|
-
leftOperand: {
|
|
91
|
-
leftOperand: 'Name',
|
|
92
|
-
operator: 'like',
|
|
93
|
-
rightOperand: ' app user', // ! will not work if the name was too long as "app user" might be cut off
|
|
94
|
-
},
|
|
95
|
-
operator: 'AND',
|
|
96
|
-
rightOperand: {
|
|
97
|
-
// this is used to filter out system generated installed packages. in our testing, at least those installed packages created in the last few years have hat set this to false while additional (hidden) installed packages have it set to true.
|
|
98
|
-
leftOperand: 'MustChangePassword',
|
|
99
|
-
operator: 'equals',
|
|
100
|
-
rightOperand: 'false',
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
};
|
|
105
|
-
if (key) {
|
|
106
|
-
// move original filter down one level into rightOperand and add key filter into leftOperand
|
|
107
|
-
requestParams = {
|
|
108
|
-
filter: {
|
|
109
|
-
leftOperand: {
|
|
110
|
-
leftOperand: 'CustomerKey',
|
|
111
|
-
operator: 'equals',
|
|
112
|
-
rightOperand: key,
|
|
113
|
-
},
|
|
114
|
-
operator: 'AND',
|
|
115
|
-
rightOperand: requestParams.filter,
|
|
116
|
-
},
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
Util.logger.info(` - Loading ${this.definition.type}. This might take a while...`);
|
|
120
|
-
return super.retrieveSOAP(retrieveDir, requestParams);
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
*
|
|
124
|
-
* @private
|
|
125
|
-
* @param {string} date first date
|
|
126
|
-
* @returns {number} time difference
|
|
127
|
-
*/
|
|
128
|
-
static _timeSinceDate(date) {
|
|
129
|
-
const interval = 'days';
|
|
130
|
-
const second = 1000,
|
|
131
|
-
minute = second * 60,
|
|
132
|
-
hour = minute * 60,
|
|
133
|
-
day = hour * 24,
|
|
134
|
-
week = day * 7;
|
|
135
|
-
date = new Date(date);
|
|
136
|
-
const now = new Date();
|
|
137
|
-
const timediff = now - date;
|
|
138
|
-
if (Number.isNaN(timediff)) {
|
|
139
|
-
return Number.NaN;
|
|
140
|
-
}
|
|
141
|
-
let result;
|
|
142
|
-
switch (interval) {
|
|
143
|
-
case 'years': {
|
|
144
|
-
result = now.getFullYear() - date.getFullYear();
|
|
145
|
-
break;
|
|
146
|
-
}
|
|
147
|
-
case 'months': {
|
|
148
|
-
result =
|
|
149
|
-
now.getFullYear() * 12 +
|
|
150
|
-
now.getMonth() -
|
|
151
|
-
(date.getFullYear() * 12 + date.getMonth());
|
|
152
|
-
break;
|
|
153
|
-
}
|
|
154
|
-
case 'weeks': {
|
|
155
|
-
result = Math.floor(timediff / week);
|
|
156
|
-
break;
|
|
157
|
-
}
|
|
158
|
-
case 'days': {
|
|
159
|
-
result = Math.floor(timediff / day);
|
|
160
|
-
break;
|
|
161
|
-
}
|
|
162
|
-
case 'hours': {
|
|
163
|
-
result = Math.floor(timediff / hour);
|
|
164
|
-
break;
|
|
165
|
-
}
|
|
166
|
-
case 'minutes': {
|
|
167
|
-
result = Math.floor(timediff / minute);
|
|
168
|
-
break;
|
|
169
|
-
}
|
|
170
|
-
case 'seconds': {
|
|
171
|
-
result = Math.floor(timediff / second);
|
|
172
|
-
break;
|
|
173
|
-
}
|
|
174
|
-
default: {
|
|
175
|
-
return;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
return result + ' ' + interval;
|
|
179
|
-
}
|
|
180
|
-
/**
|
|
181
|
-
* helper to print bu names
|
|
182
|
-
*
|
|
183
|
-
* @private
|
|
184
|
-
* @param {number} id bu id
|
|
185
|
-
* @returns {string} "bu name (bu id)""
|
|
186
|
-
*/
|
|
187
|
-
static _getBuName(id) {
|
|
188
|
-
const name = this.buObject.eid == id ? '_ParentBU_' : this.buIdName[id];
|
|
189
|
-
return `<nobr>${name} (${id})</nobr>`;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* helper that gets BU names from config
|
|
194
|
-
*
|
|
195
|
-
* @private
|
|
196
|
-
*/
|
|
197
|
-
static _getBuNames() {
|
|
198
|
-
this.buIdName = {};
|
|
199
|
-
for (const cred in this.properties.credentials) {
|
|
200
|
-
for (const buName in this.properties.credentials[cred].businessUnits) {
|
|
201
|
-
this.buIdName[this.properties.credentials[cred].businessUnits[buName]] = buName;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Creates markdown documentation of all roles
|
|
207
|
-
*
|
|
208
|
-
* @param {TYPE.MetadataTypeMap} [metadata] user list
|
|
209
|
-
* @returns {Promise.<void>} -
|
|
210
|
-
*/
|
|
211
|
-
static async document(metadata) {
|
|
212
|
-
if (this.buObject.eid !== this.buObject.mid) {
|
|
213
|
-
Util.logger.error(
|
|
214
|
-
`Users can only be retrieved & documented for the ${Util.parentBuName}`
|
|
215
|
-
);
|
|
216
|
-
return;
|
|
217
|
-
}
|
|
218
|
-
if (!metadata) {
|
|
219
|
-
// load users from disk if document was called directly and not part of a retrieve
|
|
220
|
-
try {
|
|
221
|
-
metadata = this.readBUMetadataForType(
|
|
222
|
-
File.normalizePath([
|
|
223
|
-
this.properties.directories.retrieve,
|
|
224
|
-
this.buObject.credential,
|
|
225
|
-
Util.parentBuName,
|
|
226
|
-
]),
|
|
227
|
-
true
|
|
228
|
-
).accountUser;
|
|
229
|
-
} catch (ex) {
|
|
230
|
-
Util.logger.error(ex.message);
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
// init map of BU Ids > BU Name
|
|
235
|
-
this._getBuNames();
|
|
236
|
-
|
|
237
|
-
// initialize permission object
|
|
238
|
-
this.allPermissions = {};
|
|
239
|
-
/**
|
|
240
|
-
* @type {TYPE.AccountUserDocument[]}
|
|
241
|
-
*/
|
|
242
|
-
const users = [];
|
|
243
|
-
// traverse all permissions recursively and write them into allPermissions object once it has reached the end
|
|
244
|
-
for (const id in metadata) {
|
|
245
|
-
const user = metadata[id];
|
|
246
|
-
// TODO resolve user permissions to something readable
|
|
247
|
-
let userPermissions = '';
|
|
248
|
-
if (user.UserPermissions) {
|
|
249
|
-
if (!user.UserPermissions.length) {
|
|
250
|
-
// 1 single user permission found, normalize it
|
|
251
|
-
user.UserPermissions = [user.UserPermissions];
|
|
252
|
-
}
|
|
253
|
-
userPermissions = user.UserPermissions.map((item) => item.ID * 1)
|
|
254
|
-
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))
|
|
255
|
-
.join(', ');
|
|
256
|
-
}
|
|
257
|
-
// user roles
|
|
258
|
-
// TODO think about what to do with "individual role" entries
|
|
259
|
-
let roles = '';
|
|
260
|
-
if (user.Roles) {
|
|
261
|
-
roles =
|
|
262
|
-
'<nobr>' +
|
|
263
|
-
user.Roles.map((item) => item.Name)
|
|
264
|
-
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))
|
|
265
|
-
.join(',</nobr><br> <nobr>') +
|
|
266
|
-
'</nobr>';
|
|
267
|
-
}
|
|
268
|
-
let associatedBus = '';
|
|
269
|
-
if (user.AssociatedBusinessUnits__c) {
|
|
270
|
-
user.AssociatedBusinessUnits__c.push({
|
|
271
|
-
ID: user.DefaultBusinessUnit,
|
|
272
|
-
});
|
|
273
|
-
// ensure associatedBus have no duplicates
|
|
274
|
-
associatedBus = [
|
|
275
|
-
...new Set(
|
|
276
|
-
user.AssociatedBusinessUnits__c.map((item) => this._getBuName(item.ID))
|
|
277
|
-
),
|
|
278
|
-
]
|
|
279
|
-
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0))
|
|
280
|
-
.join(',<br> ');
|
|
281
|
-
}
|
|
282
|
-
const defaultBUName = this._getBuName(user.DefaultBusinessUnit);
|
|
283
|
-
users.push({
|
|
284
|
-
TYPE: user.type__c,
|
|
285
|
-
UserID: user.UserID,
|
|
286
|
-
AccountUserID: user.AccountUserID,
|
|
287
|
-
CustomerKey: user.CustomerKey,
|
|
288
|
-
Name: user.Name,
|
|
289
|
-
Email: user.Email,
|
|
290
|
-
NotificationEmailAddress: user.NotificationEmailAddress,
|
|
291
|
-
ActiveFlag: user.ActiveFlag === true ? '✓' : '-',
|
|
292
|
-
IsAPIUser: user.IsAPIUser === true ? '✓' : '-',
|
|
293
|
-
MustChangePassword: user.MustChangePassword === true ? '✓' : '-',
|
|
294
|
-
DefaultBusinessUnit: defaultBUName,
|
|
295
|
-
AssociatedBusinessUnits__c: associatedBus,
|
|
296
|
-
Roles: roles,
|
|
297
|
-
UserPermissions: userPermissions,
|
|
298
|
-
LastSuccessfulLogin: this._timeSinceDate(user.LastSuccessfulLogin),
|
|
299
|
-
CreatedDate: user.CreatedDate.split('T').join(' '),
|
|
300
|
-
ModifiedDate: user.ModifiedDate.split('T').join(' '),
|
|
301
|
-
});
|
|
302
|
-
}
|
|
303
|
-
users.sort((a, b) => (a.Name < b.Name ? -1 : a.Name > b.Name ? 1 : 0));
|
|
304
|
-
const columnsToPrint = [
|
|
305
|
-
['Name', 'Name'],
|
|
306
|
-
['Last successful Login', 'LastSuccessfulLogin'],
|
|
307
|
-
['Active', 'ActiveFlag'],
|
|
308
|
-
['API User', 'IsAPIUser'],
|
|
309
|
-
['Must change PW', 'MustChangePassword'],
|
|
310
|
-
['Default BU', 'DefaultBusinessUnit'],
|
|
311
|
-
['BU Access', 'AssociatedBusinessUnits__c'],
|
|
312
|
-
['Roles', 'Roles'],
|
|
313
|
-
['User Permissions', 'UserPermissions'],
|
|
314
|
-
['Login', 'UserID'],
|
|
315
|
-
['ID', 'AccountUserID'],
|
|
316
|
-
['Key', 'CustomerKey'],
|
|
317
|
-
['E-Mail', 'Email'],
|
|
318
|
-
['Notification E-Mail', 'NotificationEmailAddress'],
|
|
319
|
-
['Modified Date', 'ModifiedDate'],
|
|
320
|
-
['Created Date', 'CreatedDate'],
|
|
321
|
-
];
|
|
322
|
-
let output = `# User Overview - ${this.buObject.credential}`;
|
|
323
|
-
output += this._generateDocMd(
|
|
324
|
-
users.filter((user) => user.TYPE === 'User' && user.ActiveFlag === '✓'),
|
|
325
|
-
'User',
|
|
326
|
-
columnsToPrint
|
|
327
|
-
);
|
|
328
|
-
output += this._generateDocMd(
|
|
329
|
-
users.filter((user) => user.TYPE === 'User' && user.ActiveFlag === '-'),
|
|
330
|
-
'Inactivated User',
|
|
331
|
-
columnsToPrint
|
|
332
|
-
);
|
|
333
|
-
output += this._generateDocMd(
|
|
334
|
-
users.filter((user) => user.TYPE === 'Installed Package'),
|
|
335
|
-
'Installed Package',
|
|
336
|
-
columnsToPrint
|
|
337
|
-
);
|
|
338
|
-
const docPath = File.normalizePath([this.properties.directories.docs, 'user']);
|
|
339
|
-
|
|
340
|
-
try {
|
|
341
|
-
const filename = this.buObject.credential;
|
|
342
|
-
// write to disk
|
|
343
|
-
await File.writeToFile(docPath, filename + '.accountUsers', 'md', output);
|
|
344
|
-
Util.logger.info(`Created ${File.normalizePath([docPath, filename])}.accountUsers.md`);
|
|
345
|
-
if (['html', 'both'].includes(this.properties.options.documentType)) {
|
|
346
|
-
Util.logger.warn(
|
|
347
|
-
' - HTML-based documentation of accountUser currently not supported.'
|
|
348
|
-
);
|
|
349
|
-
}
|
|
350
|
-
} catch (ex) {
|
|
351
|
-
Util.logger.error(`AccountUser.document():: error | `, ex.message);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
/**
|
|
355
|
-
*
|
|
356
|
-
* @private
|
|
357
|
-
* @param {object[]} users list of users and installed package
|
|
358
|
-
* @param {'Installed Package'|'User'} type choose what sub type to print
|
|
359
|
-
* @param {Array[]} columnsToPrint helper array
|
|
360
|
-
* @returns {string} markdown
|
|
361
|
-
*/
|
|
362
|
-
static _generateDocMd(users, type, columnsToPrint) {
|
|
363
|
-
let output = `\n\n## ${type}s (${users.length})\n\n`;
|
|
364
|
-
let tableSeparator = '';
|
|
365
|
-
for (const column of columnsToPrint) {
|
|
366
|
-
output += `| ${column[0]} `;
|
|
367
|
-
tableSeparator += '| --- ';
|
|
368
|
-
}
|
|
369
|
-
output += `|\n${tableSeparator}|\n`;
|
|
370
|
-
for (const user of users) {
|
|
371
|
-
for (const column of columnsToPrint) {
|
|
372
|
-
output += `| ${user[column[1]]} `;
|
|
373
|
-
}
|
|
374
|
-
output += `|\n`;
|
|
375
|
-
}
|
|
376
|
-
return output;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
/**
|
|
380
|
-
* manages post retrieve steps
|
|
381
|
-
*
|
|
382
|
-
* @param {TYPE.MetadataTypeItem} metadata a single query
|
|
383
|
-
* @returns {TYPE.MetadataTypeItem} Array with one metadata object and one query string
|
|
384
|
-
*/
|
|
385
|
-
static postRetrieveTasks(metadata) {
|
|
386
|
-
return this.parseMetadata(metadata);
|
|
387
|
-
}
|
|
388
|
-
/**
|
|
389
|
-
* parses retrieved Metadata before saving
|
|
390
|
-
*
|
|
391
|
-
* @param {TYPE.MetadataTypeItem} metadata a single query activity definition
|
|
392
|
-
* @returns {TYPE.MetadataTypeItem} Array with one metadata object and one sql string
|
|
393
|
-
*/
|
|
394
|
-
static parseMetadata(metadata) {
|
|
395
|
-
metadata.type__c = 'Installed Package';
|
|
396
|
-
if (metadata.Email.includes('@') && !metadata.Name.endsWith('app user')) {
|
|
397
|
-
metadata.type__c = 'User';
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
metadata.AssociatedBusinessUnits__c = this.userIdBuMap[metadata.ID] || [];
|
|
401
|
-
|
|
402
|
-
let roles;
|
|
403
|
-
if (metadata.Roles?.Role) {
|
|
404
|
-
// normalize to always use array
|
|
405
|
-
if (!metadata.Roles.Role.length) {
|
|
406
|
-
metadata.Roles.Role = [metadata.Roles.Role];
|
|
407
|
-
}
|
|
408
|
-
// convert complex object into basic set of info
|
|
409
|
-
roles = metadata.Roles.Role.map((item) => ({
|
|
410
|
-
Name: item.Name,
|
|
411
|
-
CustomerKey: item.CustomerKey,
|
|
412
|
-
})).sort((a, b) => (a.Name < b.Name ? -1 : a.Name > b.Name ? 1 : 0));
|
|
413
|
-
} else {
|
|
414
|
-
// set to empty array
|
|
415
|
-
roles = [];
|
|
416
|
-
}
|
|
417
|
-
metadata.Roles = roles;
|
|
418
|
-
|
|
419
|
-
return metadata;
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// Assign definition to static attributes
|
|
424
|
-
AccountUser.definition = require('../MetadataTypeDefinitions').accountUser;
|
|
425
|
-
|
|
426
|
-
module.exports = AccountUser;
|