const EVENT_TYPES = { ACTION_CREATE: 'actionCreate', ACTION_DELETE: 'actionDelete', ACTION_UPDATE: 'actionUpdate', ATTACHMENT_CREATE: 'attachmentCreate', ATTACHMENT_DELETE: 'attachmentDelete', ATTACHMENT_UPDATE: 'attachmentUpdate', BOARD_CREATE: 'boardCreate', BOARD_DELETE: 'boardDelete', BOARD_UPDATE: 'boardUpdate', BOARD_MEMBERSHIP_CREATE: 'boardMembershipCreate', BOARD_MEMBERSHIP_DELETE: 'boardMembershipDelete', BOARD_MEMBERSHIP_UPDATE: 'boardMembershipUpdate', CARD_CREATE: 'cardCreate', CARD_DELETE: 'cardDelete', CARD_UPDATE: 'cardUpdate', CARD_LABEL_CREATE: 'cardLabelCreate', CARD_LABEL_DELETE: 'cardLabelDelete', CARD_MEMBERSHIP_CREATE: 'cardMembershipCreate', CARD_MEMBERSHIP_DELETE: 'cardMembershipDelete', LABEL_CREATE: 'labelCreate', LABEL_DELETE: 'labelDelete', LABEL_UPDATE: 'labelUpdate', LIST_CREATE: 'listCreate', LIST_DELETE: 'listDelete', LIST_SORT: 'listSort', LIST_UPDATE: 'listUpdate', NOTIFICATION_CREATE: 'notificationCreate', NOTIFICATION_UPDATE: 'notificationUpdate', PROJECT_CREATE: 'projectCreate', PROJECT_DELETE: 'projectDelete', PROJECT_UPDATE: 'projectUpdate', PROJECT_MANAGER_CREATE: 'projectManagerCreate', PROJECT_MANAGER_DELETE: 'projectManagerDelete', TASK_CREATE: 'taskCreate', TASK_DELETE: 'taskDelete', TASK_UPDATE: 'taskUpdate', USER_CREATE: 'userCreate', USER_DELETE: 'userDelete', USER_UPDATE: 'userUpdate', }; const jsonifyData = (data) => { const nextData = {}; if (data.item) { nextData.item = sails.helpers.utils.jsonifyRecord(data.item); } if (data.items) { nextData.items = data.items.map((item) => sails.helpers.utils.jsonifyRecord(item)); } if (data.included) { nextData.included = Object.entries(data.included).reduce( (result, [key, items]) => ({ ...result, [key]: items.map((item) => sails.helpers.utils.jsonifyRecord(item)), }), {}, ); } return nextData; }; /** * Sends a webhook notification to a configured URL. * * @param {*} webhook - Webhook configuration. * @param {string} event - The event (see {@link EVENT_TYPES}). * @param {*} data - The actual data related to the event. * @param {ref} user - User object associated with the event. * @returns {Promise} */ async function sendWebhook(webhook, event, data, user) { const headers = { 'Content-Type': 'application/json', }; if (webhook.accessToken) { headers.Authorization = `Bearer ${webhook.accessToken}`; } const body = JSON.stringify({ event, data: jsonifyData(data), user: sails.helpers.utils.jsonifyRecord(user), }); const response = await fetch(webhook.url, { headers, body, method: 'POST', }); if (!response.ok) { const message = await response.text(); sails.log.error( `Webhook ${webhook.url} failed with status ${response.status} and message: ${message}`, ); } } module.exports = { sync: true, inputs: { event: { type: 'string', required: true, isIn: Object.values(EVENT_TYPES), }, data: { type: 'ref', required: true, }, user: { type: 'ref', required: true, }, }, fn(inputs) { if (!sails.config.custom.webhooks) { return; } sails.config.custom.webhooks.forEach((webhook) => { if (!webhook.url) { return; } if (webhook.excludedEvents && webhook.excludedEvents.includes(inputs.event)) { return; } if (webhook.events && !webhook.events.includes(inputs.event)) { return; } sendWebhook(webhook, inputs.event, inputs.data, inputs.user); }); }, };