mcdev 8.3.0 → 8.4.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/.github/ISSUE_TEMPLATE/bug.yml +2 -0
- package/.github/workflows/close_issues_on_merge.yml +4 -0
- package/.github/workflows/coverage-base-update.yml +2 -2
- package/.github/workflows/coverage-develop-branch.yml +1 -1
- package/.github/workflows/coverage-main-branch.yml +1 -1
- package/.github/workflows/coverage.yml +2 -2
- package/.github/workflows/npm-publish.yml +0 -2
- package/@types/lib/index.d.ts.map +1 -1
- package/@types/lib/metadataTypes/DataFilter.d.ts +19 -9
- package/@types/lib/metadataTypes/DataFilter.d.ts.map +1 -1
- package/@types/lib/metadataTypes/DataFilterHidden.d.ts +1 -0
- package/@types/lib/metadataTypes/DataFilterHidden.d.ts.map +1 -1
- package/@types/lib/metadataTypes/FileLocation.d.ts +74 -0
- package/@types/lib/metadataTypes/FileLocation.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Journey.d.ts +6 -0
- package/@types/lib/metadataTypes/Journey.d.ts.map +1 -1
- package/@types/lib/metadataTypes/MetadataType.d.ts +6 -0
- package/@types/lib/metadataTypes/MetadataType.d.ts.map +1 -1
- package/@types/lib/metadataTypes/Script.d.ts +14 -0
- package/@types/lib/metadataTypes/Script.d.ts.map +1 -1
- package/@types/lib/metadataTypes/definitions/DataFilter.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/DataFilterHidden.definition.d.ts +1 -0
- package/@types/lib/metadataTypes/definitions/FileLocation.definition.d.ts +62 -4
- package/@types/lib/metadataTypes/definitions/Journey.definition.d.ts +6 -0
- package/@types/lib/metadataTypes/definitions/Script.definition.d.ts +10 -0
- package/lib/cli.js +6 -0
- package/lib/index.js +1 -0
- package/lib/metadataTypes/DataFilter.js +82 -27
- package/lib/metadataTypes/Event.js +2 -2
- package/lib/metadataTypes/FileLocation.js +204 -4
- package/lib/metadataTypes/Journey.js +72 -45
- package/lib/metadataTypes/MetadataType.js +14 -0
- package/lib/metadataTypes/Script.js +16 -0
- package/lib/metadataTypes/definitions/DataFilter.definition.js +1 -0
- package/lib/metadataTypes/definitions/DataFilterHidden.definition.js +1 -0
- package/lib/metadataTypes/definitions/FileLocation.definition.js +52 -7
- package/lib/metadataTypes/definitions/Journey.definition.js +6 -0
- package/lib/metadataTypes/definitions/Script.definition.js +6 -0
- package/package.json +11 -11
- package/test/general.test.js +11 -11
- package/test/mockRoot/.mcdevrc.json +1 -1
- package/test/mockRoot/deploy/testInstance/testBU/asset/block/{testExisting_asset_htmlblock-matchName-fail.asset-block-meta.json → testExisting_asset_html-matchNamFail.asset-block-meta.json} +1 -1
- package/test/mockRoot/deploy/testInstance/testBU/asset/block/{testExisting_asset_htmlblock-matchName.asset-block-meta.json → testExisting_asset_html-matchName.asset-block-meta.json} +1 -1
- package/test/mockRoot/deploy/testInstance/testBU/asset/block/{testExisting_asset_htmlblock-matchName-create.asset-block-meta.json → testExisting_asset_html-matchNameAdd.asset-block-meta.json} +3 -3
- package/test/mockRoot/deploy/testInstance/testBU/fileLocation/ExactTarget Enhanced FTP.fileLocation-meta.json +5 -0
- package/test/mockRoot/deploy/testInstance/testBU/fileLocation/testExisting_fileLocation_aws.fileLocation-meta.json +14 -0
- package/test/mockRoot/deploy/testInstance/testBU/fileLocation/testExisting_fileLocation_exsftp.fileLocation-meta.json +12 -0
- package/test/resourceFactory.js +9 -2
- package/test/resources/9999999/asset/v1/content/assets/1295064/patch-response.json +1 -1
- package/test/resources/9999999/automation/v1/ftplocations/get-response.json +26 -1
- package/test/resources/9999999/automation/v1/scripts/39f6a488-20eb-4ba0-b0b9-023725b574e4/get-response.json +10 -0
- package/test/resources/9999999/automation/v1/scripts/39f6a488-20eb-4ba0-b0b9-023725b574e4/patch-response.json +2 -2
- package/test/resources/9999999/data/v1/filetransferlocation/Salesforce%20Objects%20%26%20Reports/get-response.json +4 -0
- package/test/resources/9999999/data/v1/filetransferlocation/testExisting_fileLocation_aws/patch-response.json +18 -0
- package/test/resources/9999999/data/v1/filetransferlocation/testExisting_fileLocation_azure/delete-response.json +4 -0
- package/test/resources/9999999/data/v1/filetransferlocation/testExisting_fileLocation_azure/get-response.json +18 -0
- package/test/resources/9999999/data/v1/filetransferlocation/testExisting_fileLocation_exsftp/patch-response.json +16 -0
- package/test/resources/9999999/data/v1/filetransferlocations/get-response.json +59 -0
- package/test/resources/9999999/fileLocation/build-expected.json +14 -0
- package/test/resources/9999999/fileLocation/get-aws-expected.json +14 -0
- package/test/resources/9999999/fileLocation/get-azure-expected.json +14 -0
- package/test/resources/9999999/fileLocation/get-eftp-expected.json +5 -0
- package/test/resources/9999999/fileLocation/get-exsftp-expected.json +12 -0
- package/test/resources/9999999/fileLocation/get-gcp-expected.json +10 -0
- package/test/resources/9999999/fileLocation/get-sor-expected.json +5 -0
- package/test/resources/9999999/fileLocation/patch-aws-expected.json +14 -0
- package/test/resources/9999999/fileLocation/patch-exsftp-expected.json +12 -0
- package/test/resources/9999999/fileLocation/template-expected.json +14 -0
- package/test/resources/9999999/interaction/v1/interactions/get-response-status=Published.json +40 -0
- package/test/type.asset.test.js +7 -7
- package/test/type.automation.test.js +14 -14
- package/test/type.dataFilter.test.js +10 -2
- package/test/type.fileLocation.test.js +279 -0
- package/test/type.fileTransfer.test.js +4 -4
- package/test/type.filter.test.js +9 -2
- package/test/type.importFile.test.js +5 -5
- package/test/type.journey.test.js +26 -0
- package/test/type.query.test.js +2 -2
- package/test/type.script.test.js +1 -1
- /package/test/mockRoot/deploy/testInstance/testBU/asset/block/{testExisting_asset_htmlblock-matchName-create.asset-block-meta.html → testExisting_asset_html-matchNamFail.asset-block-meta.html} +0 -0
- /package/test/mockRoot/deploy/testInstance/testBU/asset/block/{testExisting_asset_htmlblock-matchName-fail.asset-block-meta.html → testExisting_asset_html-matchName.asset-block-meta.html} +0 -0
- /package/test/mockRoot/deploy/testInstance/testBU/asset/block/{testExisting_asset_htmlblock-matchName.asset-block-meta.html → testExisting_asset_html-matchNameAdd.asset-block-meta.html} +0 -0
|
@@ -146,6 +146,16 @@ declare namespace _default {
|
|
|
146
146
|
let template_12: boolean;
|
|
147
147
|
export { template_12 as template };
|
|
148
148
|
}
|
|
149
|
+
namespace parentCategoryId {
|
|
150
|
+
let isCreateable_13: boolean;
|
|
151
|
+
export { isCreateable_13 as isCreateable };
|
|
152
|
+
let isUpdateable_13: boolean;
|
|
153
|
+
export { isUpdateable_13 as isUpdateable };
|
|
154
|
+
let retrieving_13: boolean;
|
|
155
|
+
export { retrieving_13 as retrieving };
|
|
156
|
+
let template_13: boolean;
|
|
157
|
+
export { template_13 as template };
|
|
158
|
+
}
|
|
149
159
|
namespace r__folder_Path {
|
|
150
160
|
let skipValidation: boolean;
|
|
151
161
|
}
|
package/lib/cli.js
CHANGED
|
@@ -73,6 +73,12 @@ yargs(hideBin(process.argv))
|
|
|
73
73
|
type: 'boolean',
|
|
74
74
|
group: 'Options for retrieve:',
|
|
75
75
|
describe: 'deletes the relevant retrieve folder before retrieving',
|
|
76
|
+
})
|
|
77
|
+
.option('onlyPublished', {
|
|
78
|
+
type: 'boolean',
|
|
79
|
+
alias: 'op',
|
|
80
|
+
group: 'Options for retrieve:',
|
|
81
|
+
describe: 'only retrieve the version of the metadata that was published',
|
|
76
82
|
}),
|
|
77
83
|
(argv) => {
|
|
78
84
|
Mcdev.setOptions(argv);
|
package/lib/index.js
CHANGED
|
@@ -20,6 +20,8 @@ import File from '../util/file.js';
|
|
|
20
20
|
* @typedef {import('../../types/mcdev.d.js').SoapRequestParams} SoapRequestParams
|
|
21
21
|
* @typedef {import('../../types/mcdev.d.js').TemplateMap} TemplateMap
|
|
22
22
|
* @typedef {import('../../types/mcdev.d.js').DataFilterItem} DataFilterItem
|
|
23
|
+
* @typedef {import('../../types/mcdev.d.js').DataExtensionFieldMap} DataExtensionFieldMap
|
|
24
|
+
* @typedef {import('../../types/mcdev.d.js').DataExtensionFieldItem} DataExtensionFieldItem
|
|
23
25
|
* @typedef {import('../../types/mcdev.d.js').DataFilterMap} DataFilterMap
|
|
24
26
|
* @typedef {import('../../types/mcdev.d.js').MultiMetadataTypeMap} MultiMetadataTypeMap
|
|
25
27
|
* @typedef {import('../../types/mcdev.d.js').FilterConditionSet} FilterConditionSet
|
|
@@ -108,8 +110,10 @@ class DataFilter extends MetadataType {
|
|
|
108
110
|
*/
|
|
109
111
|
static async _getFilterFolderIds(recached = false) {
|
|
110
112
|
const fromCache =
|
|
111
|
-
this.cache.folderFilter || cache.getCache().folder
|
|
112
|
-
? Object.values(
|
|
113
|
+
this.cache[this.buObject.mid]?.folderFilter || cache.getCache().folder
|
|
114
|
+
? Object.values(
|
|
115
|
+
this.cache[this.buObject.mid]?.folderFilter || cache.getCache().folder
|
|
116
|
+
)
|
|
113
117
|
.filter((item) => item.ContentType === 'filterdefinition')
|
|
114
118
|
.filter(
|
|
115
119
|
(item) =>
|
|
@@ -133,7 +137,10 @@ class DataFilter extends MetadataType {
|
|
|
133
137
|
Folder.client = this.client;
|
|
134
138
|
Folder.buObject = this.buObject;
|
|
135
139
|
Folder.properties = this.properties;
|
|
136
|
-
this.cache.
|
|
140
|
+
this.cache[this.buObject.mid] ||= {};
|
|
141
|
+
this.cache[this.buObject.mid].folderFilter = (
|
|
142
|
+
await Folder.retrieveForCache(null, subTypeArr)
|
|
143
|
+
).metadata;
|
|
137
144
|
return this._getFilterFolderIds(true);
|
|
138
145
|
}
|
|
139
146
|
/**
|
|
@@ -143,9 +150,9 @@ class DataFilter extends MetadataType {
|
|
|
143
150
|
*/
|
|
144
151
|
static async _getMeasureFolderIds() {
|
|
145
152
|
const fromCache =
|
|
146
|
-
this.cache
|
|
153
|
+
this.cache[this.buObject.mid]?.folderMeasure || cache.getCache().folder
|
|
147
154
|
? Object.values(
|
|
148
|
-
this.cache
|
|
155
|
+
this.cache[this.buObject.mid]?.folderMeasure || cache.getCache().folder
|
|
149
156
|
)
|
|
150
157
|
.filter((item) => item.ContentType === 'measure')
|
|
151
158
|
.map((item) => item.ID)
|
|
@@ -161,8 +168,9 @@ class DataFilter extends MetadataType {
|
|
|
161
168
|
Folder.client = this.client;
|
|
162
169
|
Folder.buObject = this.buObject;
|
|
163
170
|
Folder.properties = this.properties;
|
|
164
|
-
this.cache.
|
|
165
|
-
this.cache
|
|
171
|
+
this.cache[this.buObject.mid] ||= {};
|
|
172
|
+
this.cache[this.buObject.mid].folderMeasure ||= {};
|
|
173
|
+
this.cache[this.buObject.mid].folderMeasure = (
|
|
166
174
|
await Folder.retrieveForCache(null, subTypeArr)
|
|
167
175
|
).metadata;
|
|
168
176
|
return this._getMeasureFolderIds();
|
|
@@ -201,12 +209,18 @@ class DataFilter extends MetadataType {
|
|
|
201
209
|
: Object.values(metadataTypeMap)
|
|
202
210
|
.filter((item) => item.r__source_dataExtension_key)
|
|
203
211
|
.map((item) => item.r__source_dataExtension_key)
|
|
212
|
+
.filter(
|
|
213
|
+
(deKey) =>
|
|
214
|
+
!this.cache[this.buObject.mid]?.dataExtensionField ||
|
|
215
|
+
!this.cache[this.buObject.mid]?.dataExtensionField[deKey]
|
|
216
|
+
)
|
|
204
217
|
.filter(Boolean);
|
|
205
218
|
if (deKeys.length) {
|
|
219
|
+
const deKeysUnique = [...new Set(deKeys)];
|
|
206
220
|
Util.logger.info(' - Caching dependent Metadata: dataExtensionField');
|
|
207
221
|
// only proceed with the download if we have dataExtension keys
|
|
208
222
|
const fieldOptions = {};
|
|
209
|
-
for (const deKey of
|
|
223
|
+
for (const deKey of deKeysUnique) {
|
|
210
224
|
fieldOptions.filter = fieldOptions.filter
|
|
211
225
|
? {
|
|
212
226
|
leftOperand: {
|
|
@@ -226,9 +240,38 @@ class DataFilter extends MetadataType {
|
|
|
226
240
|
DataExtensionField.buObject = this.buObject;
|
|
227
241
|
DataExtensionField.client = this.client;
|
|
228
242
|
DataExtensionField.properties = this.properties;
|
|
229
|
-
this.
|
|
230
|
-
await DataExtensionField.retrieveForCacheDE(fieldOptions, ['Name', 'ObjectID'])
|
|
231
|
-
|
|
243
|
+
this.saveDataExtensionFieldCacheToMap(
|
|
244
|
+
(await DataExtensionField.retrieveForCacheDE(fieldOptions, ['Name', 'ObjectID']))
|
|
245
|
+
.metadata
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* helper for {@link DataFilter._cacheDeFields}
|
|
251
|
+
*
|
|
252
|
+
* @param {DataExtensionFieldMap} deFieldCache -
|
|
253
|
+
*/
|
|
254
|
+
static saveDataExtensionFieldCacheToMap(deFieldCache) {
|
|
255
|
+
this.cache[this.buObject.mid] ||= {};
|
|
256
|
+
this.cache[this.buObject.mid].dataExtensionField ||= {};
|
|
257
|
+
|
|
258
|
+
if (!deFieldCache) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
for (const field of Object.values(deFieldCache)) {
|
|
262
|
+
if (!field?.DataExtension?.CustomerKey) {
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
if (
|
|
266
|
+
!this.cache[this.buObject.mid].dataExtensionField[field.DataExtension.CustomerKey]
|
|
267
|
+
) {
|
|
268
|
+
/** @type {Object.<string, DataExtensionFieldItem[]>} */
|
|
269
|
+
this.cache[this.buObject.mid].dataExtensionField[field.DataExtension.CustomerKey] =
|
|
270
|
+
[];
|
|
271
|
+
}
|
|
272
|
+
this.cache[this.buObject.mid].dataExtensionField[field.DataExtension.CustomerKey].push(
|
|
273
|
+
field
|
|
274
|
+
);
|
|
232
275
|
}
|
|
233
276
|
}
|
|
234
277
|
/**
|
|
@@ -237,7 +280,7 @@ class DataFilter extends MetadataType {
|
|
|
237
280
|
* @param {DataFilterMap} metadataTypeMap -
|
|
238
281
|
*/
|
|
239
282
|
static async _cacheContactAttributes(metadataTypeMap) {
|
|
240
|
-
if (this.cache
|
|
283
|
+
if (this.cache[this.buObject.mid]?.contactAttributes) {
|
|
241
284
|
return;
|
|
242
285
|
}
|
|
243
286
|
const subscriberFilters = Object.values(metadataTypeMap)
|
|
@@ -248,8 +291,8 @@ class DataFilter extends MetadataType {
|
|
|
248
291
|
const response = await this.client.rest.get('/email/v1/Contacts/Attributes/');
|
|
249
292
|
const keyFieldBackup = this.definition.keyField;
|
|
250
293
|
this.definition.keyField = 'id';
|
|
251
|
-
this.cache.
|
|
252
|
-
this.cache
|
|
294
|
+
this.cache[this.buObject.mid] ||= {};
|
|
295
|
+
this.cache[this.buObject.mid].contactAttributes = this.parseResponseBody(response);
|
|
253
296
|
this.definition.keyField = keyFieldBackup;
|
|
254
297
|
}
|
|
255
298
|
}
|
|
@@ -259,7 +302,7 @@ class DataFilter extends MetadataType {
|
|
|
259
302
|
* @param {DataFilterMap} metadataTypeMap -
|
|
260
303
|
*/
|
|
261
304
|
static async _cacheMeasures(metadataTypeMap) {
|
|
262
|
-
if (this.cache
|
|
305
|
+
if (this.cache?.[this.buObject.mid]?.measures) {
|
|
263
306
|
return;
|
|
264
307
|
}
|
|
265
308
|
const subscriberFilters = Object.values(metadataTypeMap)
|
|
@@ -281,8 +324,8 @@ class DataFilter extends MetadataType {
|
|
|
281
324
|
|
|
282
325
|
const keyFieldBackup = this.definition.keyField;
|
|
283
326
|
this.definition.keyField = 'measureID';
|
|
284
|
-
this.cache.
|
|
285
|
-
this.cache
|
|
327
|
+
this.cache[this.buObject.mid] ||= {};
|
|
328
|
+
this.cache[this.buObject.mid].measures = this.parseResponseBody(response);
|
|
286
329
|
this.definition.keyField = keyFieldBackup;
|
|
287
330
|
}
|
|
288
331
|
}
|
|
@@ -399,7 +442,7 @@ class DataFilter extends MetadataType {
|
|
|
399
442
|
*
|
|
400
443
|
* @param {DataFilterItem} metadata -
|
|
401
444
|
* @param {'postRetrieve'|'preDeploy'} mode -
|
|
402
|
-
* @param {
|
|
445
|
+
* @param {DataExtensionFieldItem[]} [fieldCache] -
|
|
403
446
|
* @param {FilterConditionSet} [filter] -
|
|
404
447
|
* @returns {void}
|
|
405
448
|
*/
|
|
@@ -408,7 +451,9 @@ class DataFilter extends MetadataType {
|
|
|
408
451
|
return this._resolveFields(
|
|
409
452
|
metadata,
|
|
410
453
|
mode,
|
|
411
|
-
|
|
454
|
+
this.cache[this.buObject.mid].dataExtensionField[
|
|
455
|
+
metadata.r__source_dataExtension_key
|
|
456
|
+
],
|
|
412
457
|
metadata.c__filterDefinition?.ConditionSet
|
|
413
458
|
);
|
|
414
459
|
}
|
|
@@ -418,11 +463,11 @@ class DataFilter extends MetadataType {
|
|
|
418
463
|
: [filter.Condition];
|
|
419
464
|
if (mode === 'postRetrieve') {
|
|
420
465
|
for (const condition of conditionsArr) {
|
|
421
|
-
this._postRetrieve_resolveFieldIdsCondition(condition, fieldCache);
|
|
466
|
+
this._postRetrieve_resolveFieldIdsCondition(metadata, condition, fieldCache);
|
|
422
467
|
}
|
|
423
468
|
} else if (mode === 'preDeploy') {
|
|
424
469
|
for (const condition of conditionsArr) {
|
|
425
|
-
this._preDeploy_resolveFieldNamesCondition(condition, fieldCache);
|
|
470
|
+
this._preDeploy_resolveFieldNamesCondition(metadata, condition, fieldCache);
|
|
426
471
|
}
|
|
427
472
|
}
|
|
428
473
|
}
|
|
@@ -438,16 +483,21 @@ class DataFilter extends MetadataType {
|
|
|
438
483
|
/**
|
|
439
484
|
* helper for {@link _resolveFields}
|
|
440
485
|
*
|
|
486
|
+
* @param {DataFilterItem} metadata -
|
|
441
487
|
* @param {FilterCondition} condition -
|
|
442
|
-
* @param {
|
|
488
|
+
* @param {DataExtensionFieldItem[]} fieldCache -
|
|
443
489
|
* @returns {void}
|
|
444
490
|
*/
|
|
445
|
-
static _postRetrieve_resolveFieldIdsCondition(condition, fieldCache) {
|
|
491
|
+
static _postRetrieve_resolveFieldIdsCondition(metadata, condition, fieldCache) {
|
|
446
492
|
condition.r__dataExtensionField_name = fieldCache.find(
|
|
447
493
|
(field) => field.ObjectID === condition['@_ID']
|
|
448
494
|
)?.Name;
|
|
449
495
|
if (condition.r__dataExtensionField_name) {
|
|
450
496
|
delete condition['@_ID'];
|
|
497
|
+
} else {
|
|
498
|
+
Util.logger.warn(
|
|
499
|
+
` - ${this.definition.type} ${metadata[this.definition.keyField]}: could not resolve dataExtensionField with ID ${condition['@_ID']} in condition`
|
|
500
|
+
);
|
|
451
501
|
}
|
|
452
502
|
if (['IsEmpty', 'IsNotEmpty'].includes(condition['@_Operator'])) {
|
|
453
503
|
delete condition.Value;
|
|
@@ -456,16 +506,21 @@ class DataFilter extends MetadataType {
|
|
|
456
506
|
/**
|
|
457
507
|
* helper for {@link _resolveFields}
|
|
458
508
|
*
|
|
509
|
+
* @param {DataFilterItem} metadata -
|
|
459
510
|
* @param {FilterCondition} condition -
|
|
460
|
-
* @param {
|
|
511
|
+
* @param {DataExtensionFieldItem[]} fieldCache -
|
|
461
512
|
* @returns {void}
|
|
462
513
|
*/
|
|
463
|
-
static _preDeploy_resolveFieldNamesCondition(condition, fieldCache) {
|
|
514
|
+
static _preDeploy_resolveFieldNamesCondition(metadata, condition, fieldCache) {
|
|
464
515
|
condition['@_ID'] = fieldCache.find(
|
|
465
516
|
(field) => field.Name === condition.r__dataExtensionField_name
|
|
466
517
|
)?.ObjectID;
|
|
467
518
|
if (condition['@_ID']) {
|
|
468
519
|
delete condition.r__dataExtensionField_name;
|
|
520
|
+
} else {
|
|
521
|
+
throw new Error(
|
|
522
|
+
` - ${this.definition.type} ${metadata[this.definition.keyField]}: could not resolve dataExtensionField with Name ${condition.r__dataExtensionField_name} in condition`
|
|
523
|
+
);
|
|
469
524
|
}
|
|
470
525
|
if (['IsEmpty', 'IsNotEmpty'].includes(condition['@_Operator'])) {
|
|
471
526
|
condition.Value ||= '';
|
|
@@ -489,8 +544,8 @@ class DataFilter extends MetadataType {
|
|
|
489
544
|
metadata.c__filterDefinition?.ConditionSet
|
|
490
545
|
);
|
|
491
546
|
}
|
|
492
|
-
const contactAttributes = this.cache
|
|
493
|
-
const measures = this.cache
|
|
547
|
+
const contactAttributes = this.cache[this.buObject.mid]?.contactAttributes;
|
|
548
|
+
const measures = this.cache[this.buObject.mid]?.measures;
|
|
494
549
|
const conditionsArr = Array.isArray(filter.Condition)
|
|
495
550
|
? filter.Condition
|
|
496
551
|
: [filter.Condition];
|
|
@@ -1067,7 +1067,7 @@ class Event extends MetadataType {
|
|
|
1067
1067
|
if (errors.length > 1) {
|
|
1068
1068
|
errors.unshift(``);
|
|
1069
1069
|
}
|
|
1070
|
-
throw new Error(errors.join('\n · '));
|
|
1070
|
+
throw new Error(errors.join('\n · '));
|
|
1071
1071
|
}
|
|
1072
1072
|
if (warnings?.length) {
|
|
1073
1073
|
// add a line break
|
|
@@ -1220,7 +1220,7 @@ class Event extends MetadataType {
|
|
|
1220
1220
|
if (errors.length > 1) {
|
|
1221
1221
|
errors.unshift(``);
|
|
1222
1222
|
}
|
|
1223
|
-
throw new Error(errors.join('\n · '));
|
|
1223
|
+
throw new Error(errors.join('\n · '));
|
|
1224
1224
|
}
|
|
1225
1225
|
}
|
|
1226
1226
|
|
|
@@ -22,6 +22,7 @@ import { Util } from '../util/util.js';
|
|
|
22
22
|
* @augments MetadataType
|
|
23
23
|
*/
|
|
24
24
|
class FileLocation extends MetadataType {
|
|
25
|
+
static cache = {};
|
|
25
26
|
/**
|
|
26
27
|
* Retrieves Metadata of FileLocation
|
|
27
28
|
* Endpoint /automation/v1/ftplocations/ return all FileLocations
|
|
@@ -32,8 +33,32 @@ class FileLocation extends MetadataType {
|
|
|
32
33
|
* @param {string} [key] customer key of single item to retrieve
|
|
33
34
|
* @returns {Promise.<MetadataTypeMapObj>} Promise
|
|
34
35
|
*/
|
|
35
|
-
static retrieve(retrieveDir, _, __, key) {
|
|
36
|
-
|
|
36
|
+
static async retrieve(retrieveDir, _, __, key) {
|
|
37
|
+
try {
|
|
38
|
+
const dataItems = await super.retrieveREST(
|
|
39
|
+
null,
|
|
40
|
+
'/data/v1/filetransferlocation' + (key ? '/' + encodeURIComponent(key) : 's'),
|
|
41
|
+
null,
|
|
42
|
+
key
|
|
43
|
+
);
|
|
44
|
+
this.cache[this.buObject.mid] ||= {};
|
|
45
|
+
this.cache[this.buObject.mid].dataItems = dataItems.metadata;
|
|
46
|
+
} catch (ex) {
|
|
47
|
+
if (ex.code === 'ERR_BAD_REQUEST') {
|
|
48
|
+
// if retrieve-by-key comes up empty, the data-endpoint returns a code 400
|
|
49
|
+
Util.logger.debug(ex.message);
|
|
50
|
+
} else {
|
|
51
|
+
Util.logger.warn(ex.message);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const items = await super.retrieveREST(
|
|
55
|
+
retrieveDir,
|
|
56
|
+
'/automation/v1/ftplocations/',
|
|
57
|
+
null,
|
|
58
|
+
key
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
return items;
|
|
37
62
|
}
|
|
38
63
|
|
|
39
64
|
/**
|
|
@@ -42,9 +67,156 @@ class FileLocation extends MetadataType {
|
|
|
42
67
|
* @returns {Promise.<MetadataTypeMapObj>} Promise
|
|
43
68
|
*/
|
|
44
69
|
static async retrieveForCache() {
|
|
45
|
-
return
|
|
70
|
+
return this.retrieve(null);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Creates a single item
|
|
75
|
+
*
|
|
76
|
+
* @param {MetadataTypeItem} metadata a single item
|
|
77
|
+
* @returns {Promise.<MetadataTypeItem>} Promise
|
|
78
|
+
*/
|
|
79
|
+
static create(metadata) {
|
|
80
|
+
return this.createREST(metadata, '/data/v1/filetransferlocation');
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Updates a single item
|
|
84
|
+
*
|
|
85
|
+
* @param {MetadataTypeItem} metadata a single item
|
|
86
|
+
* @returns {Promise.<MetadataTypeItem>} Promise
|
|
87
|
+
*/
|
|
88
|
+
static update(metadata) {
|
|
89
|
+
return this.updateREST(
|
|
90
|
+
metadata,
|
|
91
|
+
'/data/v1/filetransferlocation/' +
|
|
92
|
+
encodeURIComponent(metadata[this.definition.keyField])
|
|
93
|
+
);
|
|
46
94
|
}
|
|
47
95
|
|
|
96
|
+
/**
|
|
97
|
+
* helper for {@link MetadataType.parseResponseBody} that creates a custom key field for this type based on mobileCode and keyword
|
|
98
|
+
*
|
|
99
|
+
* @param {MetadataTypeItem} metadata single item
|
|
100
|
+
*/
|
|
101
|
+
static createCustomKeyField(metadata) {
|
|
102
|
+
if (metadata.fileTransferLocation) {
|
|
103
|
+
const fileTransferLocation = metadata.fileTransferLocation;
|
|
104
|
+
for (const key of Object.keys(metadata)) {
|
|
105
|
+
delete metadata[key];
|
|
106
|
+
}
|
|
107
|
+
Object.assign(metadata, fileTransferLocation);
|
|
108
|
+
} else {
|
|
109
|
+
if (!metadata.customerKey && this.cache[this.buObject.mid]?.dataItems) {
|
|
110
|
+
const nameMatch = Object.values(this.cache[this.buObject.mid].dataItems).find(
|
|
111
|
+
(item) => item.name === metadata.name
|
|
112
|
+
);
|
|
113
|
+
if (nameMatch) {
|
|
114
|
+
Object.assign(metadata, nameMatch);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (!this.definition.locationTypeIdMappingDeployable[metadata.locationTypeId]) {
|
|
118
|
+
// old file location types are only returned by the automation-endpoint which does not return customerKey field - but also these are not updatable and hence we can improvise here
|
|
119
|
+
|
|
120
|
+
metadata.customerKey ||= metadata.name;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Creates a single metadata entry via REST
|
|
127
|
+
*
|
|
128
|
+
* @param {MetadataTypeItem} metadataEntry a single metadata Entry
|
|
129
|
+
* @param {string} uri rest endpoint for POST
|
|
130
|
+
* @param {boolean} [handleOutside] if the API reponse is irregular this allows you to handle it outside of this generic method
|
|
131
|
+
* @returns {Promise.<object> | null} Promise of API response or null in case of an error
|
|
132
|
+
*/
|
|
133
|
+
static async createREST(metadataEntry, uri, handleOutside) {
|
|
134
|
+
this.removeNotCreateableFields(metadataEntry);
|
|
135
|
+
const createPayload = { fileTransferLocation: metadataEntry };
|
|
136
|
+
try {
|
|
137
|
+
// set to empty object in case API returned nothing to be able to update it in helper classes
|
|
138
|
+
let response = (await this.client.rest.post(uri, createPayload)) || {};
|
|
139
|
+
response = await this.postCreateTasks(metadataEntry, response);
|
|
140
|
+
if (!handleOutside) {
|
|
141
|
+
Util.logger.info(
|
|
142
|
+
` - created ${Util.getTypeKeyName(this.definition, metadataEntry)}`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
return response;
|
|
146
|
+
} catch (ex) {
|
|
147
|
+
const parsedErrors = this.getErrorsREST(ex);
|
|
148
|
+
Util.logger.error(
|
|
149
|
+
` ☇ error creating ${Util.getTypeKeyName(this.definition, metadataEntry)}:`
|
|
150
|
+
);
|
|
151
|
+
if (parsedErrors.length) {
|
|
152
|
+
for (const msg of parsedErrors) {
|
|
153
|
+
Util.logger.error(' • ' + msg);
|
|
154
|
+
}
|
|
155
|
+
} else if (ex?.message) {
|
|
156
|
+
Util.logger.debug(ex.message);
|
|
157
|
+
}
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* helper for {@link MetadataType.createREST}
|
|
164
|
+
*
|
|
165
|
+
* @param {MetadataTypeItem} _ a single metadata Entry
|
|
166
|
+
* @param {object} apiResponse varies depending on the API call
|
|
167
|
+
* @returns {Promise.<object>} apiResponse, potentially modified
|
|
168
|
+
*/
|
|
169
|
+
static async postCreateTasks(_, apiResponse) {
|
|
170
|
+
return apiResponse?.fileTransferLocation || apiResponse;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Updates a single metadata entry via REST
|
|
175
|
+
*
|
|
176
|
+
* @param {MetadataTypeItem} metadataEntry a single metadata Entry
|
|
177
|
+
* @param {string} uri rest endpoint for PATCH
|
|
178
|
+
* @param {'patch'|'post'|'put'} [httpMethod] defaults to 'patch'; some update requests require PUT instead of PATCH
|
|
179
|
+
* @param {boolean} [handleOutside] if the API reponse is irregular this allows you to handle it outside of this generic method
|
|
180
|
+
* @returns {Promise.<object> | null} Promise of API response or null in case of an error
|
|
181
|
+
*/
|
|
182
|
+
static async updateREST(metadataEntry, uri, httpMethod = 'patch', handleOutside) {
|
|
183
|
+
this.removeNotUpdateableFields(metadataEntry);
|
|
184
|
+
const updatePayload = { fileTransferLocation: metadataEntry };
|
|
185
|
+
try {
|
|
186
|
+
// set to empty object in case API returned nothing to be able to update it in helper classes
|
|
187
|
+
let response = (await this.client.rest[httpMethod](uri, updatePayload)) || {};
|
|
188
|
+
await this._postChangeKeyTasks(metadataEntry);
|
|
189
|
+
this.getErrorsREST(response);
|
|
190
|
+
response = await this.postUpdateTasks(metadataEntry, response);
|
|
191
|
+
// some times, e.g. automation dont return a key in their update response and hence we need to fall back to name
|
|
192
|
+
if (!handleOutside) {
|
|
193
|
+
Util.logger.info(
|
|
194
|
+
` - updated ${Util.getTypeKeyName(this.definition, metadataEntry)}`
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
return response;
|
|
198
|
+
} catch (ex) {
|
|
199
|
+
const parsedErrors = this.getErrorsREST(ex);
|
|
200
|
+
Util.logger.error(
|
|
201
|
+
` ☇ error updating ${Util.getTypeKeyName(this.definition, metadataEntry)}:`
|
|
202
|
+
);
|
|
203
|
+
for (const msg of parsedErrors) {
|
|
204
|
+
Util.logger.error(' • ' + msg);
|
|
205
|
+
}
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* helper for {@link MetadataType.updateREST} and {@link MetadataType.updateSOAP}
|
|
212
|
+
*
|
|
213
|
+
* @param {MetadataTypeItem} _ a single metadata Entry
|
|
214
|
+
* @param {object} apiResponse varies depending on the API call
|
|
215
|
+
* @returns {Promise.<object>} apiResponse, potentially modified
|
|
216
|
+
*/
|
|
217
|
+
static postUpdateTasks(_, apiResponse) {
|
|
218
|
+
return apiResponse?.fileTransferLocation || apiResponse;
|
|
219
|
+
}
|
|
48
220
|
/**
|
|
49
221
|
* prepares a import definition for deployment
|
|
50
222
|
*
|
|
@@ -54,6 +226,14 @@ class FileLocation extends MetadataType {
|
|
|
54
226
|
static async preDeployTasks(metadata) {
|
|
55
227
|
if (metadata.c__locationType) {
|
|
56
228
|
metadata.locationTypeId = this.definition.locationTypeMapping[metadata.c__locationType];
|
|
229
|
+
if (this.definition.locationTypeMappingDeployable[metadata.c__locationType]) {
|
|
230
|
+
metadata.locationType =
|
|
231
|
+
this.definition.locationTypeMappingDeployable[metadata.c__locationType];
|
|
232
|
+
} else {
|
|
233
|
+
throw new Error(
|
|
234
|
+
`Only FileLocations of types ${Object.keys(this.definition.locationTypeMappingDeployable).join(', ')} can be deployed via mcdev.`
|
|
235
|
+
);
|
|
236
|
+
}
|
|
57
237
|
}
|
|
58
238
|
return metadata;
|
|
59
239
|
}
|
|
@@ -65,7 +245,7 @@ class FileLocation extends MetadataType {
|
|
|
65
245
|
* @returns {MetadataTypeItem} parsed metadata
|
|
66
246
|
*/
|
|
67
247
|
static postRetrieveTasks(metadata) {
|
|
68
|
-
if (metadata.locationTypeId) {
|
|
248
|
+
if (metadata.locationTypeId !== undefined) {
|
|
69
249
|
try {
|
|
70
250
|
metadata.c__locationType = Util.inverseGet(
|
|
71
251
|
this.definition.locationTypeMapping,
|
|
@@ -78,9 +258,29 @@ class FileLocation extends MetadataType {
|
|
|
78
258
|
metadata.locationTypeId
|
|
79
259
|
);
|
|
80
260
|
}
|
|
261
|
+
} else if (metadata.locationType) {
|
|
262
|
+
// assuming create/update of new types
|
|
263
|
+
metadata.c__locationType = Util.inverseGet(
|
|
264
|
+
this.definition.locationTypeMappingDeployable,
|
|
265
|
+
metadata.locationType
|
|
266
|
+
);
|
|
81
267
|
}
|
|
82
268
|
return metadata;
|
|
83
269
|
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Delete a metadata item from the specified business unit
|
|
273
|
+
*
|
|
274
|
+
* @param {string} key Identifier of item
|
|
275
|
+
* @returns {Promise.<boolean>} deletion success flag
|
|
276
|
+
*/
|
|
277
|
+
static async deleteByKey(key) {
|
|
278
|
+
return super.deleteByKeyREST(
|
|
279
|
+
'/data/v1/filetransferlocation/' + encodeURIComponent(key),
|
|
280
|
+
key,
|
|
281
|
+
400
|
|
282
|
+
);
|
|
283
|
+
}
|
|
84
284
|
}
|
|
85
285
|
|
|
86
286
|
// Assign definition to static attributes
|