Skip to content

Commit

Permalink
#37: add support to update/create automation wait activities
Browse files Browse the repository at this point in the history
  • Loading branch information
JoernBerkefeld committed Nov 4, 2024
1 parent bf124ba commit 3e3687d
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 9 deletions.
6 changes: 6 additions & 0 deletions @types/lib/metadataTypes/Automation.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion @types/lib/metadataTypes/Automation.d.ts.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

127 changes: 122 additions & 5 deletions lib/metadataTypes/Automation.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,20 +159,103 @@ class Automation extends MetadataType {
`/legacy/v1/beta/bulk/automations/automation/definition/`
);
this.definition.bodyIteratorField = iteratorBackup;
const automationLegacyMap = Object.keys(automationLegacyMapObj.metadata)
const notificationLegacyMap = Object.keys(automationLegacyMapObj.metadata)
.filter((key) => foundKeys.includes(key))
// ! using the `id` field to retrieve notifications does not work. instead one needs to use the URL in the `notifications` field
.map((key) => {
const steps = automationLegacyMapObj.metadata[key].processes;
// wait activities
if (steps.length) {
for (const step of steps) {
if (step.workers) {
for (const activity of step.workers) {
if (activity.objectTypeId === 467 && activity.serializedObject) {
const waitObj = JSON.parse(activity.serializedObject);
if (waitObj.timeZone) {
// add timezone to the wait activity
metadataMap[key].steps[step.sequence].activities[
activity.sequence
].timeZone = waitObj.timeZone;
}
// * wait activities are not supported in the new API
}
}
}
}
}
// notifications
return {
id: automationLegacyMapObj.metadata[key].id,
key,
};
});
const waitLegacyMap = Object.keys(automationLegacyMapObj.metadata)
.filter((key) => foundKeys.includes(key))
// ! using the `id` field to retrieve notifications does not work. instead one needs to use the URL in the `notifications` field
.filter((key) => {
const steps = automationLegacyMapObj.metadata[key].processes;
// wait activities
for (const step of steps) {
for (const activity of step.workerCounts) {
if (activity.objectTypeId === 467) {
return true;
}
}
}
})
// wait
.map((key) => ({
id: automationLegacyMapObj.metadata[key].id,
key,
}));

// get notifications for each automation
const rateLimit = pLimit(5);
await Promise.all(
waitLegacyMap.map((automationLegacy) =>
// notifications
rateLimit(async () => {
// this is a file so extended is at another endpoint
try {
const waitResult = await this.client.rest.get(
`/legacy/v1/beta/bulk/automations/automation/definition/` +
automationLegacy.id
);
if (Array.isArray(waitResult?.processes)) {
const steps = waitResult.processes;
// wait activities
for (const step of steps) {
for (const activity of step.workers) {
if (
activity.objectTypeId === 467 &&
activity.serializedObject
) {
const waitObj = JSON.parse(activity.serializedObject);
if (waitObj.timeZone) {
// add timezone to the wait activity
metadataMap[automationLegacy.key].steps[
step.sequence
].activities[activity.sequence].timeZone =
waitObj.timeZone;
}
// * wait activities are not supported in the new API
}
}
}
}
} catch (ex) {
Util.logger.debug(
` ☇ issue retrieving wait details for automation ${automationLegacy.key}: ${ex.message} ${ex.code}`
);
}
})
)
);
let found = 0;
let skipped = 0;
const promiseMap = await Promise.all(
automationLegacyMap.map((automationLegacy) =>
const notificationPromiseMap = await Promise.all(
notificationLegacyMap.map((automationLegacy) =>
// notifications
rateLimit(async () => {
// this is a file so extended is at another endpoint
try {
Expand Down Expand Up @@ -213,7 +296,7 @@ class Automation extends MetadataType {
Util.logger.debug(
`Notifications not found for ${skipped} automation${skipped === 1 ? '' : 's'}`
);
return promiseMap;
return notificationPromiseMap;
}

/**
Expand Down Expand Up @@ -889,6 +972,37 @@ class Automation extends MetadataType {
Definitions[activity.r__type].nameField
);
}
if (activity.r__type === 'wait') {
const [waitDuration, waitUnit] = activity.name.split(' ');
const waitDurationNumber = Number(waitDuration);
const allowedWaitUnits = [
'Minutes',
'Hours',
'Days',
'Weeks',
'Months',
'Years',
];
if (waitDurationNumber && allowedWaitUnits.includes(waitUnit)) {
// @ts-expect-error - serializedObject is only used to create/update wait activities
activity.serializedObject = JSON.stringify({
duration: waitDurationNumber,
durationUnits: waitUnit,
});
} else if (waitUnit === 'AM' || waitUnit === 'PM') {
let waitTime = waitDuration;
if (waitUnit === 'PM') {
waitTime =
(Number(waitTime.split(':')[0]) + 12).toString() + ':00';
}
// @ts-expect-error - serializedObject is only used to create/update wait activities
activity.serializedObject = JSON.stringify({
specifiedTime: waitTime,
// @ts-expect-error - timeZone is only used to create/update wait activities
timeZone: activity.timeZone || 'GMT Standard Time',
});
}
}
activity.objectTypeId =
this.definition.activityTypeMapping[activity.r__type];
delete activity.r__key;
Expand Down Expand Up @@ -949,7 +1063,10 @@ class Automation extends MetadataType {
);
}
// cannot deploy because it is not supported
else if (!this.definition.dependencies.includes(activity.r__type)) {
else if (
!this.definition.customDeployTypes.includes(activity.r__type) &&
!this.definition.dependencies.includes(activity.r__type)
) {
errors.push(
` • not supported ${activity.r__type} activity '${activity.r__key || activity.name}' in step ${stepNumber}.${displayOrder}`
);
Expand Down
14 changes: 11 additions & 3 deletions lib/metadataTypes/definitions/Automation.definition.js
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,8 @@ export default {
'Used via Automation Studio directly - or indirectly via Journey Builder & MC Connect.',
typeRetrieveByDefault: true,
typeName: 'Automation',
manualDeployTypes: ['wait'],
customDeployTypes: ['wait'],
manualDeployTypes: [],
fields: {
categoryId: {
isCreateable: true,
Expand Down Expand Up @@ -574,8 +575,8 @@ export default {
template: false,
},
'steps[].activities[].serializedObject': {
isCreateable: false,
isUpdateable: false,
isCreateable: true,
isUpdateable: true,
retrieving: false,
template: false,
},
Expand All @@ -585,6 +586,13 @@ export default {
'steps[].activities[].r__key': {
skipValidation: true,
},
'steps[].activities[].timeZone': {
// used for wait actitivity
isCreateable: false,
isUpdateable: false,
retrieving: true,
template: true,
},
'steps[].description': {
isCreateable: true,
isUpdateable: true,
Expand Down

0 comments on commit 3e3687d

Please sign in to comment.