mcdev 4.1.12 → 4.2.1
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/.eslintrc.json +1 -1
- package/.github/ISSUE_TEMPLATE/bug.yml +1 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +2 -3
- package/.nycrc.json +5 -0
- package/README.md +34 -1528
- package/boilerplate/config.json +2 -6
- package/boilerplate/files/.vscode/extensions.json +1 -0
- package/boilerplate/files/.vscode/settings.json +3 -0
- package/docs/dist/documentation.md +437 -31
- package/lib/Deployer.js +10 -8
- package/lib/MetadataTypeDefinitions.js +3 -0
- package/lib/MetadataTypeInfo.js +3 -0
- package/lib/Retriever.js +14 -7
- package/lib/cli.js +1 -0
- package/lib/index.js +6 -6
- package/lib/metadataTypes/AccountUser.js +2 -2
- package/lib/metadataTypes/Asset.js +45 -35
- package/lib/metadataTypes/Automation.js +4 -4
- package/lib/metadataTypes/DataExtension.js +14 -8
- package/lib/metadataTypes/DataExtensionField.js +44 -9
- package/lib/metadataTypes/Discovery.js +5 -5
- package/lib/metadataTypes/Folder.js +30 -6
- package/lib/metadataTypes/List.js +115 -17
- package/lib/metadataTypes/MetadataType.js +73 -40
- package/lib/metadataTypes/Query.js +2 -2
- package/lib/metadataTypes/Script.js +2 -2
- package/lib/metadataTypes/TransactionalEmail.js +163 -0
- package/lib/metadataTypes/TransactionalMessage.js +127 -0
- package/lib/metadataTypes/TransactionalPush.js +77 -0
- package/lib/metadataTypes/TransactionalSMS.js +354 -0
- package/lib/metadataTypes/TriggeredSendDefinition.js +11 -9
- package/lib/metadataTypes/definitions/TransactionalEmail.definition.js +145 -0
- package/lib/metadataTypes/definitions/TransactionalPush.definition.js +109 -0
- package/lib/metadataTypes/definitions/TransactionalSMS.definition.js +103 -0
- package/lib/metadataTypes/definitions/TriggeredSendDefinition.definition.js +36 -36
- package/lib/util/auth.js +2 -2
- package/lib/util/businessUnit.js +1 -1
- package/lib/util/cli.js +19 -20
- package/lib/util/config.js +13 -12
- package/lib/util/devops.js +4 -4
- package/lib/util/init.config.js +7 -7
- package/lib/util/init.git.js +11 -23
- package/lib/util/init.js +67 -3
- package/lib/util/util.js +20 -12
- package/package.json +19 -12
- package/test/dataExtension.test.js +36 -19
- package/test/mockRoot/.mcdevrc.json +13 -2
- package/test/mockRoot/deploy/testInstance/testBU/dataExtension/childBU_dataextension_test.dataExtension-meta.json +27 -7
- package/test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.json +1 -1
- package/test/mockRoot/deploy/testInstance/testBU/query/testExistingQuery.query-meta.sql +3 -1
- package/test/mockRoot/deploy/testInstance/testBU/query/{testQuery.query-meta.json → testNewQuery.query-meta.json} +3 -3
- package/test/mockRoot/deploy/testInstance/testBU/query/{testQuery.query-meta.sql → testNewQuery.query-meta.sql} +0 -0
- package/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testExisting_temail.transactionalEmail-meta.json +24 -0
- package/test/mockRoot/deploy/testInstance/testBU/transactionalEmail/testNew_temail.transactionalEmail-meta.json +24 -0
- package/test/mockRoot/deploy/testInstance/testBU/transactionalPush/testExisting_tpush.transactionalPush-meta.json +18 -0
- package/test/mockRoot/deploy/testInstance/testBU/transactionalPush/testNew_tpush.transactionalPush-meta.json +18 -0
- package/test/mockRoot/deploy/testInstance/testBU/transactionalSMS/testExisting_tsms.transactionalSMS-meta.amp +4 -0
- package/test/mockRoot/deploy/testInstance/testBU/transactionalSMS/testExisting_tsms.transactionalSMS-meta.json +15 -0
- package/test/mockRoot/deploy/testInstance/testBU/transactionalSMS/testNew_tsms.transactionalSMS-meta.amp +4 -0
- package/test/mockRoot/deploy/testInstance/testBU/transactionalSMS/testNew_tsms.transactionalSMS-meta.json +15 -0
- package/test/query.test.js +57 -23
- package/test/resources/1111111/businessUnit/retrieve-response.xml +33 -0
- package/test/resources/1111111/list/retrieve-response.xml +39 -0
- package/test/resources/9999999/asset/v1/content/assets/query/post-response.json +72 -0
- package/test/resources/9999999/automation/v1/queries/549f0568-607c-4940-afef-437965094dat/patch-response.json +2 -2
- package/test/resources/9999999/automation/v1/queries/get-response.json +2 -2
- package/test/resources/9999999/automation/v1/queries/post-response.json +3 -3
- package/test/resources/9999999/dataExtension/build-expected.json +2 -2
- package/test/resources/9999999/dataFolder/retrieve-response.xml +95 -2
- package/test/resources/9999999/interaction/v1/interactions/get-response.json +296 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/code/get-response.json +32 -0
- package/test/resources/9999999/legacy/v1/beta/mobile/keyword/get-response.json +46 -0
- package/test/resources/9999999/list/retrieve-response.xml +78 -0
- package/test/resources/9999999/messaging/v1/email/definitions/get-response.json +15 -0
- package/test/resources/9999999/messaging/v1/email/definitions/post-response.json +19 -0
- package/test/resources/9999999/messaging/v1/email/definitions/testExisting_temail/get-response.json +26 -0
- package/test/resources/9999999/messaging/v1/email/definitions/testExisting_temail/patch-response.json +26 -0
- package/test/resources/9999999/messaging/v1/push/definitions/get-response.json +15 -0
- package/test/resources/9999999/messaging/v1/push/definitions/post-response.json +13 -0
- package/test/resources/9999999/messaging/v1/push/definitions/testExisting_tpush/get-response.json +13 -0
- package/test/resources/9999999/messaging/v1/push/definitions/testExisting_tpush/patch-response.json +13 -0
- package/test/resources/9999999/messaging/v1/sms/definitions/get-response.json +15 -0
- package/test/resources/9999999/messaging/v1/sms/definitions/post-response.json +17 -0
- package/test/resources/9999999/messaging/v1/sms/definitions/testExisting_tsms/get-response.json +18 -0
- package/test/resources/9999999/messaging/v1/sms/definitions/testExisting_tsms/patch-response.json +18 -0
- package/test/resources/9999999/query/build-expected.json +2 -2
- package/test/resources/9999999/query/build-expected.sql +6 -0
- package/test/resources/9999999/query/get-expected.json +1 -1
- package/test/resources/9999999/query/get-expected.sql +6 -0
- package/test/resources/9999999/query/patch-expected.json +1 -1
- package/test/resources/9999999/query/patch-expected.sql +6 -0
- package/test/resources/9999999/query/post-expected.json +3 -3
- package/test/resources/9999999/query/post-expected.sql +4 -0
- package/test/resources/9999999/query/template-expected.json +1 -1
- package/test/resources/9999999/query/template-expected.sql +6 -0
- package/test/resources/9999999/transactionalEmail/build-expected.json +22 -0
- package/test/resources/9999999/transactionalEmail/get-expected.json +24 -0
- package/test/resources/9999999/transactionalEmail/patch-expected.json +24 -0
- package/test/resources/9999999/transactionalEmail/post-expected.json +24 -0
- package/test/resources/9999999/transactionalEmail/template-expected.json +22 -0
- package/test/resources/9999999/transactionalPush/build-expected.json +8 -0
- package/test/resources/9999999/transactionalPush/get-expected.json +11 -0
- package/test/resources/9999999/transactionalPush/patch-expected.json +16 -0
- package/test/resources/9999999/transactionalPush/post-expected.json +16 -0
- package/test/resources/9999999/transactionalPush/template-expected.json +8 -0
- package/test/resources/9999999/transactionalSMS/build-expected.amp +4 -0
- package/test/resources/9999999/transactionalSMS/build-expected.json +13 -0
- package/test/resources/9999999/transactionalSMS/get-expected.amp +4 -0
- package/test/resources/9999999/transactionalSMS/get-expected.json +15 -0
- package/test/resources/9999999/transactionalSMS/patch-expected.amp +4 -0
- package/test/resources/9999999/transactionalSMS/patch-expected.json +15 -0
- package/test/resources/9999999/transactionalSMS/post-expected.amp +4 -0
- package/test/resources/9999999/transactionalSMS/post-expected.json +15 -0
- package/test/resources/9999999/transactionalSMS/template-expected.amp +4 -0
- package/test/resources/9999999/transactionalSMS/template-expected.json +13 -0
- package/test/transactionalEmail.test.js +120 -0
- package/test/transactionalPush.test.js +120 -0
- package/test/transactionalSMS.test.js +149 -0
- package/test/utils.js +57 -8
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const TYPE = require('../../types/mcdev.d');
|
|
4
|
+
const MetadataType = require('./MetadataType');
|
|
5
|
+
const Util = require('../util/util');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* TransactionalMessage MetadataType
|
|
9
|
+
*
|
|
10
|
+
* @augments MetadataType
|
|
11
|
+
*/
|
|
12
|
+
class TransactionalMessage extends MetadataType {
|
|
13
|
+
// define this.subType as string here for intellisense; requires to be redefined in child class
|
|
14
|
+
static subType;
|
|
15
|
+
/**
|
|
16
|
+
* Retrieves Metadata of Mobile Keywords
|
|
17
|
+
* Endpoint /legacy/v1/beta/mobile/code/ return all Mobile Codes with all details.
|
|
18
|
+
*
|
|
19
|
+
* @param {string} retrieveDir Directory where retrieved metadata directory will be saved
|
|
20
|
+
* @param {void} [_] unused parameter
|
|
21
|
+
* @param {void} [__] unused parameter
|
|
22
|
+
* @param {void} [___] unused parameter
|
|
23
|
+
* @param {string} [key] customer key of single item to retrieve
|
|
24
|
+
* @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise of metadata
|
|
25
|
+
*/
|
|
26
|
+
static async retrieve(retrieveDir, _, __, ___, key) {
|
|
27
|
+
let keyList;
|
|
28
|
+
const baseUri = '/messaging/v1/' + this.subType + '/definitions/';
|
|
29
|
+
if (key) {
|
|
30
|
+
// Retrieve single
|
|
31
|
+
keyList = [key];
|
|
32
|
+
} else {
|
|
33
|
+
// Retrieve all
|
|
34
|
+
const response = this.definition.restPagination
|
|
35
|
+
? await this.client.rest.getBulk(baseUri)
|
|
36
|
+
: await this.client.rest.get(baseUri);
|
|
37
|
+
const parsed = this.parseResponseBody(response);
|
|
38
|
+
keyList = Object.keys(parsed).filter((item) => parsed[item].status !== 'Deleted');
|
|
39
|
+
const filteredCount = Object.keys(parsed).length - keyList.length;
|
|
40
|
+
if (filteredCount) {
|
|
41
|
+
Util.logger.info(
|
|
42
|
+
` - Filtered ${this.definition.type} with status 'deleted': ${filteredCount} (downloaded but not saved to disk)`
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// get all sms with additional details not given by the list endpoint
|
|
48
|
+
const details = (
|
|
49
|
+
await Promise.all(
|
|
50
|
+
keyList.map(async (key) => {
|
|
51
|
+
try {
|
|
52
|
+
return await this.client.rest.get(baseUri + (key || ''));
|
|
53
|
+
} catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
)
|
|
58
|
+
).filter(Boolean);
|
|
59
|
+
const parsed = this.parseResponseBody({ definitions: details });
|
|
60
|
+
|
|
61
|
+
// * retrieveDir is mandatory in this method as it is not used for caching (there is a seperate method for that)
|
|
62
|
+
const savedMetadata = await this.saveResults(parsed, retrieveDir, null, null);
|
|
63
|
+
// defined colors for optionally printing the keys we filtered by
|
|
64
|
+
const color = {
|
|
65
|
+
reset: '\x1B[0m',
|
|
66
|
+
dim: '\x1B[2m',
|
|
67
|
+
};
|
|
68
|
+
Util.logger.info(
|
|
69
|
+
`Downloaded: ${this.definition.type} (${Object.keys(savedMetadata).length})` +
|
|
70
|
+
(key === null ? '' : ` ${color.dim}(Key: ${key})${color.reset}`)
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
return { metadata: savedMetadata, type: this.definition.type };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Retrieves event definition metadata for caching
|
|
78
|
+
*
|
|
79
|
+
* @returns {Promise.<TYPE.MetadataTypeMapObj>} Promise of metadata
|
|
80
|
+
*/
|
|
81
|
+
static retrieveForCache() {
|
|
82
|
+
return super.retrieveREST(null, '/messaging/v1/' + this.subType + '/definitions/');
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Updates a single item
|
|
86
|
+
*
|
|
87
|
+
* @param {TYPE.MetadataTypeItem} metadata a single item
|
|
88
|
+
* @returns {Promise} Promise
|
|
89
|
+
*/
|
|
90
|
+
static update(metadata) {
|
|
91
|
+
return super.updateREST(
|
|
92
|
+
metadata,
|
|
93
|
+
'/messaging/v1/' + this.subType + '/definitions/' + metadata[this.definition.keyField]
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Creates a single item
|
|
99
|
+
*
|
|
100
|
+
* @param {TYPE.MetadataTypeItem} metadata a single item
|
|
101
|
+
* @returns {Promise} Promise
|
|
102
|
+
*/
|
|
103
|
+
static create(metadata) {
|
|
104
|
+
return super.createREST(metadata, '/messaging/v1/' + this.subType + '/definitions');
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Delete a metadata item from the specified business unit
|
|
108
|
+
*
|
|
109
|
+
* @param {TYPE.BuObject} buObject references credentials
|
|
110
|
+
* @param {string} key Identifier of item
|
|
111
|
+
* @returns {Promise.<boolean>} deletion success status
|
|
112
|
+
*/
|
|
113
|
+
static deleteByKey(buObject, key) {
|
|
114
|
+
return super.deleteByKeyREST(
|
|
115
|
+
buObject,
|
|
116
|
+
'/messaging/v1/' + this.subType + '/definitions/' + key,
|
|
117
|
+
key,
|
|
118
|
+
false
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Assign definition to static attributes
|
|
124
|
+
// ! using SMS definitions here as placeholder to have auto completion
|
|
125
|
+
TransactionalMessage.definition = require('../MetadataTypeDefinitions').transactionalSMS;
|
|
126
|
+
|
|
127
|
+
module.exports = TransactionalMessage;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const TYPE = require('../../types/mcdev.d');
|
|
4
|
+
const TransactionalMessage = require('./TransactionalMessage');
|
|
5
|
+
const Util = require('../util/util');
|
|
6
|
+
const cache = require('../util/cache');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* TransactionalPush TransactionalMessage
|
|
10
|
+
*
|
|
11
|
+
* @augments TransactionalMessage
|
|
12
|
+
*/
|
|
13
|
+
class TransactionalPush extends TransactionalMessage {
|
|
14
|
+
static subType = 'push';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* prepares for deployment
|
|
18
|
+
*
|
|
19
|
+
* @param {TYPE.MetadataTypeItem} metadata a single item
|
|
20
|
+
* @returns {TYPE.MetadataTypeItem} Promise
|
|
21
|
+
*/
|
|
22
|
+
static async preDeployTasks(metadata) {
|
|
23
|
+
// asset
|
|
24
|
+
if (metadata.content?.customerKey) {
|
|
25
|
+
// we merely want to be able to show an error if it does not exist
|
|
26
|
+
cache.searchForField(
|
|
27
|
+
'asset',
|
|
28
|
+
metadata.content.customerKey,
|
|
29
|
+
'customerKey',
|
|
30
|
+
'customerKey'
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
if (metadata.options?.badge && typeof metadata.options?.badge !== 'string') {
|
|
34
|
+
// ensure it's a string, or else the API will return an error. Our SDK turns numbers in strings into actual numbers
|
|
35
|
+
metadata.options.badge += '';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return metadata;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* manages post retrieve steps
|
|
42
|
+
*
|
|
43
|
+
* @param {TYPE.MetadataTypeItem} metadata a single item
|
|
44
|
+
* @returns {TYPE.MetadataTypeItem} a single item
|
|
45
|
+
*/
|
|
46
|
+
static postRetrieveTasks(metadata) {
|
|
47
|
+
// asset
|
|
48
|
+
if (metadata.content?.customerKey) {
|
|
49
|
+
try {
|
|
50
|
+
// we merely want to be able to show an error if it does not exist
|
|
51
|
+
cache.searchForField(
|
|
52
|
+
'asset',
|
|
53
|
+
metadata.content.customerKey,
|
|
54
|
+
'customerKey',
|
|
55
|
+
'customerKey'
|
|
56
|
+
);
|
|
57
|
+
} catch (ex) {
|
|
58
|
+
Util.logger.warn(
|
|
59
|
+
` - ${this.definition.type} ${metadata[this.definition.nameField]} (${
|
|
60
|
+
metadata[this.definition.keyField]
|
|
61
|
+
}): ${ex.message}.`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (metadata.options?.badge && typeof metadata.options?.badge !== 'string') {
|
|
66
|
+
// ensure it's a string, or else the API will return an error. Our SDK turns numbers in strings into actual numbers
|
|
67
|
+
metadata.options.badge += '';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return metadata;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Assign definition to static attributes
|
|
75
|
+
TransactionalPush.definition = require('../MetadataTypeDefinitions').transactionalPush;
|
|
76
|
+
|
|
77
|
+
module.exports = TransactionalPush;
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const TYPE = require('../../types/mcdev.d');
|
|
4
|
+
const TransactionalMessage = require('./TransactionalMessage');
|
|
5
|
+
const Util = require('../util/util');
|
|
6
|
+
const File = require('../util/file');
|
|
7
|
+
const beautifier = require('beauty-amp-core');
|
|
8
|
+
const cache = require('../util/cache');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* TransactionalSMS MetadataType
|
|
12
|
+
*
|
|
13
|
+
* @augments TransactionalMessage
|
|
14
|
+
*/
|
|
15
|
+
class TransactionalSMS extends TransactionalMessage {
|
|
16
|
+
static subType = 'sms';
|
|
17
|
+
/**
|
|
18
|
+
* clean up after deleting a metadata item
|
|
19
|
+
*
|
|
20
|
+
* @param {TYPE.BuObject} buObject references credentials
|
|
21
|
+
* @param {string} customerKey Identifier of metadata item
|
|
22
|
+
* @returns {void}
|
|
23
|
+
*/
|
|
24
|
+
static async postDeleteTasks(buObject, customerKey) {
|
|
25
|
+
// delete local copy: retrieve/cred/bu/type/...json
|
|
26
|
+
const fileName = File.normalizePath([
|
|
27
|
+
this.properties.directories.retrieve,
|
|
28
|
+
buObject.credential,
|
|
29
|
+
buObject.businessUnit,
|
|
30
|
+
this.definition.type,
|
|
31
|
+
`${customerKey}.${this.definition.type}-meta.`,
|
|
32
|
+
]);
|
|
33
|
+
await File.remove(fileName + 'json');
|
|
34
|
+
await File.remove(fileName + 'amp');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* prepares for deployment
|
|
39
|
+
*
|
|
40
|
+
* @param {TYPE.MetadataTypeItem} metadata a single item
|
|
41
|
+
* @param {string} dir directory of deploy files
|
|
42
|
+
* @returns {TYPE.MetadataTypeItem} Promise
|
|
43
|
+
*/
|
|
44
|
+
static async preDeployTasks(metadata, dir) {
|
|
45
|
+
// code
|
|
46
|
+
metadata.content = {
|
|
47
|
+
message: await this._mergeCode(metadata, dir),
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
if (this._isHTML(metadata.content?.message)) {
|
|
51
|
+
// keep this as a non-blocking warning because the test not 100% accurate
|
|
52
|
+
Util.logger.warn(
|
|
53
|
+
` - ${this.definition.type} ${metadata[this.definition.nameField]} (${
|
|
54
|
+
metadata[this.definition.keyField]
|
|
55
|
+
}): HTML detected`
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// subscriptions: mobileCode
|
|
60
|
+
if (metadata.subscriptions?.shortCode) {
|
|
61
|
+
// we merely want to be able to show an error if it does not exist
|
|
62
|
+
cache.searchForField('mobileCode', metadata.subscriptions.shortCode, 'code', 'code');
|
|
63
|
+
}
|
|
64
|
+
// subscriptions: mobileKeyword
|
|
65
|
+
if (metadata.subscriptions?.keyword) {
|
|
66
|
+
// we merely want to be able to show an error if it does not exist
|
|
67
|
+
cache.searchForField(
|
|
68
|
+
'mobileKeyword',
|
|
69
|
+
metadata.subscriptions.keyword,
|
|
70
|
+
'keyword',
|
|
71
|
+
'keyword'
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
return metadata;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* helper for {@link preDeployTasks} that loads extracted code content back into JSON
|
|
78
|
+
*
|
|
79
|
+
* @param {TYPE.MetadataTypeItem} metadata a single definition
|
|
80
|
+
* @param {string} deployDir directory of deploy files
|
|
81
|
+
* @param {string} [templateName] name of the template used to built defintion (prior applying templating)
|
|
82
|
+
* @returns {Promise.<string>} content for metadata.script
|
|
83
|
+
*/
|
|
84
|
+
static async _mergeCode(metadata, deployDir, templateName) {
|
|
85
|
+
templateName = templateName || metadata[this.definition.keyField];
|
|
86
|
+
const codePath = File.normalizePath([
|
|
87
|
+
deployDir,
|
|
88
|
+
this.definition.type,
|
|
89
|
+
templateName + '.' + this.definition.type + '-meta',
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
if (await File.pathExists(codePath + '.amp')) {
|
|
93
|
+
return await File.readFilteredFilename(
|
|
94
|
+
[deployDir, this.definition.type],
|
|
95
|
+
templateName + '.' + this.definition.type + '-meta',
|
|
96
|
+
'amp'
|
|
97
|
+
);
|
|
98
|
+
} else {
|
|
99
|
+
throw new Error(`Could not find ${codePath}.amp`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* manages post retrieve steps
|
|
104
|
+
*
|
|
105
|
+
* @param {TYPE.MetadataTypeItem} metadata a single item
|
|
106
|
+
* @returns {TYPE.CodeExtractItem} Array with one metadata object and one ssjs string
|
|
107
|
+
*/
|
|
108
|
+
static postRetrieveTasks(metadata) {
|
|
109
|
+
// extract message body
|
|
110
|
+
const codeArr = [];
|
|
111
|
+
// keep between tags
|
|
112
|
+
const { fileExt, code } = this.prepExtractedCode(metadata.content?.message);
|
|
113
|
+
delete metadata.content;
|
|
114
|
+
codeArr.push({
|
|
115
|
+
subFolder: null,
|
|
116
|
+
fileName: metadata[this.definition.keyField],
|
|
117
|
+
fileExt: fileExt,
|
|
118
|
+
content: code,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
if (this._isHTML(code)) {
|
|
122
|
+
Util.logger.warn(
|
|
123
|
+
` - ${this.definition.type} ${metadata[this.definition.nameField]} (${
|
|
124
|
+
metadata[this.definition.keyField]
|
|
125
|
+
}): HTML detected`
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// subscriptions: mobileCode
|
|
130
|
+
if (metadata.subscriptions?.shortCode) {
|
|
131
|
+
try {
|
|
132
|
+
// we merely want to be able to show a warning if it does not exist
|
|
133
|
+
cache.searchForField(
|
|
134
|
+
'mobileCode',
|
|
135
|
+
metadata.subscriptions.shortCode,
|
|
136
|
+
'code',
|
|
137
|
+
'code'
|
|
138
|
+
);
|
|
139
|
+
} catch {
|
|
140
|
+
Util.logger.warn(
|
|
141
|
+
` - ${this.definition.type} ${metadata[this.definition.nameField]} (${
|
|
142
|
+
metadata[this.definition.keyField]
|
|
143
|
+
}): Could not find mobileCode ${metadata.subscriptions.shortCode}.`
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// subscriptions: mobileKeyword
|
|
148
|
+
if (metadata.subscriptions?.keyword) {
|
|
149
|
+
try {
|
|
150
|
+
// we merely want to be able to show a warning if it does not exist
|
|
151
|
+
cache.searchForField(
|
|
152
|
+
'mobileKeyword',
|
|
153
|
+
metadata.subscriptions.keyword,
|
|
154
|
+
'keyword',
|
|
155
|
+
'keyword'
|
|
156
|
+
);
|
|
157
|
+
} catch {
|
|
158
|
+
Util.logger.warn(
|
|
159
|
+
` - ${this.definition.type} ${metadata[this.definition.nameField]} (${
|
|
160
|
+
metadata[this.definition.keyField]
|
|
161
|
+
}): Could not find mobileKeyword ${metadata.subscriptions.keyword}.`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return { json: metadata, codeArr: codeArr, subFolder: null };
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* helper for {@link parseMetadata} and {@link _buildForNested}
|
|
170
|
+
*
|
|
171
|
+
* @param {string} metadataScript the code of the file
|
|
172
|
+
* @returns {{fileExt:string,code:string}} returns found extension and file content
|
|
173
|
+
*/
|
|
174
|
+
static prepExtractedCode(metadataScript) {
|
|
175
|
+
// immutable at the moment:
|
|
176
|
+
const ampscript = {
|
|
177
|
+
capitalizeAndOrNot: true,
|
|
178
|
+
capitalizeIfFor: true,
|
|
179
|
+
capitalizeSet: true,
|
|
180
|
+
capitalizeVar: true,
|
|
181
|
+
maxParametersPerLine: 4,
|
|
182
|
+
};
|
|
183
|
+
// immutable at the moment:
|
|
184
|
+
const editor = {
|
|
185
|
+
insertSpaces: true,
|
|
186
|
+
tabSize: 4,
|
|
187
|
+
};
|
|
188
|
+
// logs trough console only for the moment.
|
|
189
|
+
const logs = {
|
|
190
|
+
loggerOn: false, // <= disable logging
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
beautifier.setup(ampscript, editor, logs);
|
|
194
|
+
const code = beautifier.beautify(metadataScript);
|
|
195
|
+
const fileExt = 'amp';
|
|
196
|
+
|
|
197
|
+
return { fileExt, code };
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* helper for {@link MetadataType.buildDefinition}
|
|
201
|
+
* handles extracted code if any are found for complex types
|
|
202
|
+
*
|
|
203
|
+
* @param {string} templateDir Directory where metadata templates are stored
|
|
204
|
+
* @param {string|string[]} targetDir (List of) Directory where built definitions will be saved
|
|
205
|
+
* @param {TYPE.MetadataTypeItem} metadata main JSON file that was read from file system
|
|
206
|
+
* @param {TYPE.TemplateMap} templateVariables variables to be replaced in the metadata
|
|
207
|
+
* @param {string} templateName name of the template to be built
|
|
208
|
+
* @returns {Promise.<string[][]>} list of extracted files with path-parts provided as an array
|
|
209
|
+
*/
|
|
210
|
+
static buildDefinitionForNested(
|
|
211
|
+
templateDir,
|
|
212
|
+
targetDir,
|
|
213
|
+
metadata,
|
|
214
|
+
templateVariables,
|
|
215
|
+
templateName
|
|
216
|
+
) {
|
|
217
|
+
return this._buildForNested(
|
|
218
|
+
templateDir,
|
|
219
|
+
targetDir,
|
|
220
|
+
metadata,
|
|
221
|
+
templateVariables,
|
|
222
|
+
templateName,
|
|
223
|
+
'definition'
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* helper for {@link MetadataType.buildTemplate}
|
|
228
|
+
* handles extracted code if any are found for complex types
|
|
229
|
+
*
|
|
230
|
+
* @example scripts are saved as 1 json and 1 ssjs file. both files need to be run through templating
|
|
231
|
+
* @param {string} templateDir Directory where metadata templates are stored
|
|
232
|
+
* @param {string|string[]} targetDir (List of) Directory where built definitions will be saved
|
|
233
|
+
* @param {TYPE.MetadataTypeItem} metadata main JSON file that was read from file system
|
|
234
|
+
* @param {TYPE.TemplateMap} templateVariables variables to be replaced in the metadata
|
|
235
|
+
* @param {string} templateName name of the template to be built
|
|
236
|
+
* @returns {Promise.<string[][]>} list of extracted files with path-parts provided as an array
|
|
237
|
+
*/
|
|
238
|
+
static buildTemplateForNested(
|
|
239
|
+
templateDir,
|
|
240
|
+
targetDir,
|
|
241
|
+
metadata,
|
|
242
|
+
templateVariables,
|
|
243
|
+
templateName
|
|
244
|
+
) {
|
|
245
|
+
return this._buildForNested(
|
|
246
|
+
templateDir,
|
|
247
|
+
targetDir,
|
|
248
|
+
metadata,
|
|
249
|
+
templateVariables,
|
|
250
|
+
templateName,
|
|
251
|
+
'template'
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* helper for {@link buildTemplateForNested} / {@link buildDefinitionForNested}
|
|
257
|
+
* handles extracted code if any are found for complex types
|
|
258
|
+
*
|
|
259
|
+
* @param {string} templateDir Directory where metadata templates are stored
|
|
260
|
+
* @param {string|string[]} targetDir (List of) Directory where built definitions will be saved
|
|
261
|
+
* @param {TYPE.MetadataTypeItem} metadata main JSON file that was read from file system
|
|
262
|
+
* @param {TYPE.TemplateMap} templateVariables variables to be replaced in the metadata
|
|
263
|
+
* @param {string} templateName name of the template to be built
|
|
264
|
+
* @param {'definition'|'template'} mode defines what we use this helper for
|
|
265
|
+
* @returns {Promise.<string[][]>} list of extracted files with path-parts provided as an array
|
|
266
|
+
*/
|
|
267
|
+
static async _buildForNested(
|
|
268
|
+
templateDir,
|
|
269
|
+
targetDir,
|
|
270
|
+
metadata,
|
|
271
|
+
templateVariables,
|
|
272
|
+
templateName,
|
|
273
|
+
mode
|
|
274
|
+
) {
|
|
275
|
+
// get code from filesystem
|
|
276
|
+
let code = await this._mergeCode(metadata, templateDir, templateName);
|
|
277
|
+
const file = this.prepExtractedCode(code, metadata.name);
|
|
278
|
+
const fileExt = file.fileExt;
|
|
279
|
+
code = file.code;
|
|
280
|
+
// apply templating
|
|
281
|
+
try {
|
|
282
|
+
if (mode === 'definition') {
|
|
283
|
+
// replace template variables with their values
|
|
284
|
+
code = this.applyTemplateValues(code, templateVariables);
|
|
285
|
+
} else if (mode === 'template') {
|
|
286
|
+
// replace template values with corresponding variable names
|
|
287
|
+
code = this.applyTemplateNames(code, templateVariables);
|
|
288
|
+
}
|
|
289
|
+
} catch {
|
|
290
|
+
throw new Error(
|
|
291
|
+
`${this.definition.type}:: Error applying template variables on ${
|
|
292
|
+
templateName + '.' + this.definition.type
|
|
293
|
+
}-meta.${fileExt}.`
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// write to file
|
|
298
|
+
const targetDirArr = Array.isArray(targetDir) ? targetDir : [targetDir];
|
|
299
|
+
const nestedFilePaths = [];
|
|
300
|
+
|
|
301
|
+
// keep old name if creating templates, otherwise use new name
|
|
302
|
+
const fileName = mode === 'definition' ? metadata[this.definition.keyField] : templateName;
|
|
303
|
+
|
|
304
|
+
for (const targetDir of targetDirArr) {
|
|
305
|
+
File.writeToFile(
|
|
306
|
+
[targetDir, this.definition.type],
|
|
307
|
+
fileName + '.' + this.definition.type + '-meta',
|
|
308
|
+
fileExt,
|
|
309
|
+
code
|
|
310
|
+
);
|
|
311
|
+
nestedFilePaths.push([
|
|
312
|
+
targetDir,
|
|
313
|
+
this.definition.type,
|
|
314
|
+
fileName + '.' + this.definition.type + '-meta.' + fileExt,
|
|
315
|
+
]);
|
|
316
|
+
}
|
|
317
|
+
return nestedFilePaths;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* very simplified test for HTML code in our SMS
|
|
321
|
+
*
|
|
322
|
+
* @param {string} code sms source code
|
|
323
|
+
* @returns {boolean} true if HTML is found
|
|
324
|
+
*/
|
|
325
|
+
static _isHTML(code) {
|
|
326
|
+
return /(<([^>]+)>)/gi.test(code);
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* should return only the json for all but asset, query and script that are saved as multiple files
|
|
330
|
+
* additionally, the documentation for dataExtension and automation should be returned
|
|
331
|
+
*
|
|
332
|
+
* @param {string[]} keyArr customerkey of the metadata
|
|
333
|
+
* @returns {string[]} list of all files that need to be committed in a flat array ['path/file1.ext', 'path/file2.ext']
|
|
334
|
+
*/
|
|
335
|
+
static getFilesToCommit(keyArr) {
|
|
336
|
+
const path = File.normalizePath([
|
|
337
|
+
this.properties.directories.retrieve,
|
|
338
|
+
this.buObject.credential,
|
|
339
|
+
this.buObject.businessUnit,
|
|
340
|
+
this.definition.type,
|
|
341
|
+
]);
|
|
342
|
+
|
|
343
|
+
const fileList = keyArr.flatMap((key) => [
|
|
344
|
+
File.normalizePath([path, `${key}.${this.definition.type}-meta.json`]),
|
|
345
|
+
File.normalizePath([path, `${key}.${this.definition.type}-meta.amp`]),
|
|
346
|
+
]);
|
|
347
|
+
return fileList;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// Assign definition to static attributes
|
|
352
|
+
TransactionalSMS.definition = require('../MetadataTypeDefinitions').transactionalSMS;
|
|
353
|
+
|
|
354
|
+
module.exports = TransactionalSMS;
|
|
@@ -169,14 +169,16 @@ class TriggeredSendDefinition extends MetadataType {
|
|
|
169
169
|
);
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
|
-
// List
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
172
|
+
// List (optional)
|
|
173
|
+
if (metadata.List) {
|
|
174
|
+
try {
|
|
175
|
+
metadata.r__list_PathName = cache.getListPathName(metadata.List.ID, 'ID');
|
|
176
|
+
delete metadata.List;
|
|
177
|
+
} catch (ex) {
|
|
178
|
+
Util.logger.warn(
|
|
179
|
+
` - ${this.definition.typeName} '${metadata.Name}'/'${metadata.CustomerKey}': ${ex.message}`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
180
182
|
}
|
|
181
183
|
|
|
182
184
|
return metadata;
|
|
@@ -227,7 +229,7 @@ class TriggeredSendDefinition extends MetadataType {
|
|
|
227
229
|
`r__assetMessage_Key / r__email_Name not defined but instead found Email.ID. Please try re-retrieving this TSD from your BU.`
|
|
228
230
|
);
|
|
229
231
|
}
|
|
230
|
-
// get List
|
|
232
|
+
// get List (optional)
|
|
231
233
|
if (metadata.r__list_PathName) {
|
|
232
234
|
metadata.List = {
|
|
233
235
|
ID: cache.getListObjectId(metadata.r__list_PathName, 'ID'),
|