feat: Webhooks configuration, all events support, refactoring
parent
3779bdb053
commit
c065566c15
@ -0,0 +1,14 @@
|
|||||||
|
module.exports = {
|
||||||
|
sync: true,
|
||||||
|
|
||||||
|
inputs: {
|
||||||
|
record: {
|
||||||
|
type: 'ref',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
fn(inputs) {
|
||||||
|
return inputs.record.toJSON ? inputs.record.toJSON() : inputs.record;
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -1,115 +0,0 @@
|
|||||||
const EVENT_TYPES = {
|
|
||||||
ACTION_CREATE: 'action_create',
|
|
||||||
ACTION_UPDATE: 'action_update',
|
|
||||||
ACTION_DELETE: 'action_delete',
|
|
||||||
|
|
||||||
CARD_CREATE: 'card_create',
|
|
||||||
CARD_UPDATE: 'card_update',
|
|
||||||
CARD_DELETE: 'card_delete',
|
|
||||||
|
|
||||||
CARD_MEMBERSHIP_CREATE: 'card_membership_create',
|
|
||||||
CARD_MEMBERSHIP_DELETE: 'card_membership_delete',
|
|
||||||
|
|
||||||
LIST_CREATE: 'list_create',
|
|
||||||
LIST_UPDATE: 'list_update',
|
|
||||||
LIST_DELETE: 'list_delete',
|
|
||||||
|
|
||||||
BOARD_CREATE: 'board_create',
|
|
||||||
BOARD_UPDATE: 'board_update',
|
|
||||||
BOARD_DELETE: 'board_delete',
|
|
||||||
|
|
||||||
ATTACHMENT_CREATE: 'attachment_create',
|
|
||||||
ATTACHMENT_UPDATE: 'attachment_update',
|
|
||||||
ATTACHMENT_DELETE: 'attachment_delete',
|
|
||||||
|
|
||||||
PROJECT_CREATE: 'project_create',
|
|
||||||
PROJECT_UPDATE: 'project_update',
|
|
||||||
PROJECT_DELETE: 'project_delete',
|
|
||||||
|
|
||||||
TASK_CREATE: 'task_create',
|
|
||||||
TASK_UPDATE: 'task_update',
|
|
||||||
TASK_DELETE: 'task_delete',
|
|
||||||
|
|
||||||
USER_CREATE: 'user_create',
|
|
||||||
USER_UPDATE: 'user_update',
|
|
||||||
USER_DELETE: 'user_delete',
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends a webhook notification to a configured URL.
|
|
||||||
*
|
|
||||||
* @param {Object} inputs - Data to include in the webhook payload.
|
|
||||||
* @param {string} inputs.event - The event type (see {@link EVENT_TYPES}).
|
|
||||||
* @param {*} inputs.data - The actual data related to the event.
|
|
||||||
* @param {string} inputs.projectId - The project ID associated with the event.
|
|
||||||
* @param {ref} [inputs.user] - Optional user object associated with the event.
|
|
||||||
* @param {ref} [inputs.card] - Optional card object associated with the event.
|
|
||||||
* @param {ref} [inputs.board] - Optional board object associated with the event.
|
|
||||||
* @param {ref} [inputs.list] - Optional list object associated with the event.
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
async function sendWebhook(inputs) {
|
|
||||||
const url = sails.config.custom.webhookUrl;
|
|
||||||
const headers = {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
};
|
|
||||||
if (sails.config.custom.webhookBearer) {
|
|
||||||
headers.Authorization = `Bearer ${sails.config.custom.webhookBearer}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const body = JSON.stringify({
|
|
||||||
...inputs,
|
|
||||||
user: {
|
|
||||||
...inputs.user,
|
|
||||||
password: undefined,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const req = await fetch(url, {
|
|
||||||
method: 'POST',
|
|
||||||
headers,
|
|
||||||
body,
|
|
||||||
});
|
|
||||||
if (req.status !== 200) {
|
|
||||||
sails.log.error(`Webhook failed with status ${req.status} and message: ${await req.text()}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
eventTypes: EVENT_TYPES,
|
|
||||||
inputs: {
|
|
||||||
event: {
|
|
||||||
type: 'string',
|
|
||||||
isIn: Object.keys(EVENT_TYPES),
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
type: 'ref',
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
projectId: {
|
|
||||||
type: 'string',
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
user: {
|
|
||||||
type: 'ref',
|
|
||||||
},
|
|
||||||
card: {
|
|
||||||
type: 'ref',
|
|
||||||
},
|
|
||||||
board: {
|
|
||||||
type: 'ref',
|
|
||||||
},
|
|
||||||
list: {
|
|
||||||
type: 'ref',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
async fn(inputs) {
|
|
||||||
if (!sails.config.custom.webhookUrl) return;
|
|
||||||
try {
|
|
||||||
await sendWebhook(inputs);
|
|
||||||
} catch (err) {
|
|
||||||
sails.log.error(err);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
@ -0,0 +1,103 @@
|
|||||||
|
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 Events}).
|
||||||
|
* @param {*} data - The actual data related to the event.
|
||||||
|
* @param {ref} user - User object associated with the event.
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue