The edit campaign endpoint in the REST API is very limited: it only allows changing name, alias, description and isPublished. There’s no way to edit the actual campaign flowchart through the API.
Our use case is that we have a campaign that is re-used every few months to send 30+ emails, each scheduled on a particular date. To update the dates manually is tedious and error-prone. (The “after a relative time period” option doesn’t work for us, because late subscribers are not supposed to lag behind; they should receive each email at the same moment as everyone else.)
I appreciate that such an API will be more difficult to implement than simple scalar field editing, but it would be very useful for us.
Right now I have a snippet of JavaScript, which I paste into my browser’s developer console while I have the Campaign Builder open. It talks to the DOM to automate all the clicking and field editing, but of course it’s a horrid hack and might break with every new Mautic update.
2 Likes
Hi @thomastc!
did you get any updates on this issue?
and can you share that Script, which you’re currently using talk to the DOM?
Thanks,
1 Like
I discovered that editing campaigns through the API is supported after all; it’s just not documented. At least, that’s what my notes say… we changed our campaign structure so that the ugly script wasn’t needed anymore.
But here’s the script for reference:
(function($, startDateStr) {
function delay(millis) {
return new Promise((resolve, reject) => {
window.setTimeout(resolve, millis)
})
}
function waitFor(queryFn, testFn, timeoutMillis) {
if (timeoutMillis === undefined) {
timeoutMillis = 5000
}
const deadline = Date.now() + timeoutMillis
return new Promise((resolve, reject) => {
const intervalId = window.setInterval(() => {
if (Date.now() < deadline) {
const result = queryFn()
if (testFn(result)) {
window.clearInterval(intervalId)
resolve(result)
}
} else {
window.clearInterval(intervalId)
reject(`Timed out after ${timeoutMillis} ms waiting for ${queryFn} to pass test ${testFn}`)
}
}, 100)
})
}
function presence(queryFn, timeoutMillis) {
return waitFor(queryFn, (result) => result.length > 0, timeoutMillis)
}
function hidden(queryFn, timeoutMillis) {
return waitFor(queryFn, (result) => result.is(':visible'), timeoutMillis)
}
async function run(startDate) {
const sendEvents = []
$('.list-campaign-event').each(function(i, box) {
const $box = $(box)
const name = $box.find('.campaign-event-name').text()
const match = /Dag\s+(\d+)(?:\D|$)/.exec(name)
if (match) {
const dayOffset = parseInt(match[1]) - 1
const sendDate = new Date(startDate)
sendDate.setDate(sendDate.getDate() + dayOffset)
sendEvents.push({$box, name, sendDate})
}
})
for (const {$box, name, sendDate} of sendEvents) {
console.log(`Setting date on ${name} to ${sendDate}...`)
$box.find('.btn-edit').click()
const $modal = await presence(() => $('#CampaignEventModal'))
const executeAtDateBtn = await presence(() => $modal.find('[name="campaignevent[triggerMode]"][value="date"]'))
executeAtDateBtn.click()
const dateInput = await presence(() => $modal.find('[name="campaignevent[triggerDate]"]'))
dateInput.val(sendDate.toISOString().substr(0, 16).replace('T', ' '))
const updateBtn = $modal.find('.btn-save')
updateBtn.click()
await hidden(() => $('#CampaignEventModal'))
// Not sure why this is needed.
await delay(1000)
}
}
run(Date.parse(startDateStr)).catch((err) => console.error(err))
})(jQuery, '2020-01-01T05:00:00Z')
1 Like
you’re talking about campaign builder, right?
can you also guide me regarding that as well?
Thanks in Advance.
1 Like
Hey @thomastc, we’ve also just stumbled upon this issue. No matter what we pass under events
, the campaign will not get edited / updated, unless it is being created. In that case everything under events is respected.
Have you found a solution? It feels weird to have to delete & re-create a campaign each time you want to update it via the API.
1 Like