diff --git a/server/.env.sample b/server/.env.sample index 15d66ed75..b4fb6605e 100644 --- a/server/.env.sample +++ b/server/.env.sample @@ -46,6 +46,9 @@ SECRET_KEY=notsecretkey # SLACK_BOT_TOKEN= # SLACK_CHANNEL_ID= +# WEBHOOK_URL= +# WEBHOOK_BEARER= + ## Do not edit this TZ=UTC diff --git a/server/api/controllers/attachments/create.js b/server/api/controllers/attachments/create.js index bab6e1385..1ffe96278 100644 --- a/server/api/controllers/attachments/create.js +++ b/server/api/controllers/attachments/create.js @@ -44,7 +44,7 @@ module.exports = { async fn(inputs, exits) { const { currentUser } = this.req; - const { card } = await sails.helpers.cards + const { card, board } = await sails.helpers.cards .getProjectPath(inputs.cardId) .intercept('pathNotFound', () => Errors.CARD_NOT_FOUND); @@ -88,6 +88,7 @@ module.exports = { card, creatorUser: currentUser, }, + board, requestId: inputs.requestId, request: this.req, }); diff --git a/server/api/controllers/card-memberships/create.js b/server/api/controllers/card-memberships/create.js index c5ee73f76..9143cc910 100755 --- a/server/api/controllers/card-memberships/create.js +++ b/server/api/controllers/card-memberships/create.js @@ -45,7 +45,7 @@ module.exports = { async fn(inputs) { const { currentUser } = this.req; - const { card } = await sails.helpers.cards + const { card, board } = await sails.helpers.cards .getProjectPath(inputs.cardId) .intercept('pathNotFound', () => Errors.CARD_NOT_FOUND); @@ -74,6 +74,7 @@ module.exports = { card, userId: inputs.userId, }, + board, request: this.req, }) .intercept('userAlreadyCardMember', () => Errors.USER_ALREADY_CARD_MEMBER); diff --git a/server/api/controllers/card-memberships/delete.js b/server/api/controllers/card-memberships/delete.js index d2107309f..4b9d75471 100755 --- a/server/api/controllers/card-memberships/delete.js +++ b/server/api/controllers/card-memberships/delete.js @@ -39,7 +39,7 @@ module.exports = { async fn(inputs) { const { currentUser } = this.req; - const { board } = await sails.helpers.cards + const { board, card } = await sails.helpers.cards .getProjectPath(inputs.cardId) .intercept('pathNotFound', () => Errors.CARD_NOT_FOUND); @@ -67,6 +67,7 @@ module.exports = { cardMembership = await sails.helpers.cardMemberships.deleteOne.with({ board, + card, record: cardMembership, request: this.req, }); diff --git a/server/api/controllers/comment-actions/delete.js b/server/api/controllers/comment-actions/delete.js index b09ce2626..97c98790f 100755 --- a/server/api/controllers/comment-actions/delete.js +++ b/server/api/controllers/comment-actions/delete.js @@ -36,7 +36,7 @@ module.exports = { .intercept('pathNotFound', () => Errors.COMMENT_ACTION_NOT_FOUND); let { action } = path; - const { board, project } = path; + const { board, project, card } = path; const isProjectManager = await sails.helpers.users.isProjectManager(currentUser.id, project.id); @@ -61,6 +61,7 @@ module.exports = { action = await sails.helpers.actions.deleteOne.with({ board, + card, record: action, request: this.req, }); diff --git a/server/api/controllers/comment-actions/update.js b/server/api/controllers/comment-actions/update.js index fc5dffb98..a385ae8c5 100755 --- a/server/api/controllers/comment-actions/update.js +++ b/server/api/controllers/comment-actions/update.js @@ -40,7 +40,7 @@ module.exports = { .intercept('pathNotFound', () => Errors.COMMENT_ACTION_NOT_FOUND); let { action } = path; - const { board, project } = path; + const { board, project, card } = path; const isProjectManager = await sails.helpers.users.isProjectManager(currentUser.id, project.id); @@ -69,6 +69,7 @@ module.exports = { action = await sails.helpers.actions.updateOne.with({ values, + card, board, record: action, request: this.req, diff --git a/server/api/controllers/lists/delete.js b/server/api/controllers/lists/delete.js index 44cb48b49..982b0f73d 100755 --- a/server/api/controllers/lists/delete.js +++ b/server/api/controllers/lists/delete.js @@ -28,7 +28,8 @@ module.exports = { async fn(inputs) { const { currentUser } = this.req; - let { list } = await sails.helpers.lists + // eslint-disable-next-line prefer-const + let { list, board } = await sails.helpers.lists .getProjectPath(inputs.id) .intercept('pathNotFound', () => Errors.LIST_NOT_FOUND); @@ -47,6 +48,7 @@ module.exports = { list = await sails.helpers.lists.deleteOne.with({ record: list, + board, request: this.req, }); diff --git a/server/api/controllers/lists/update.js b/server/api/controllers/lists/update.js index 2cb34e256..15f5f209f 100755 --- a/server/api/controllers/lists/update.js +++ b/server/api/controllers/lists/update.js @@ -35,7 +35,8 @@ module.exports = { async fn(inputs) { const { currentUser } = this.req; - let { list } = await sails.helpers.lists + // eslint-disable-next-line prefer-const + let { list, board } = await sails.helpers.lists .getProjectPath(inputs.id) .intercept('pathNotFound', () => Errors.LIST_NOT_FOUND); @@ -56,6 +57,7 @@ module.exports = { list = await sails.helpers.lists.updateOne.with({ values, + board, record: list, request: this.req, }); diff --git a/server/api/controllers/tasks/create.js b/server/api/controllers/tasks/create.js index 0d2b5a41b..ff4b05237 100755 --- a/server/api/controllers/tasks/create.js +++ b/server/api/controllers/tasks/create.js @@ -39,7 +39,7 @@ module.exports = { async fn(inputs) { const { currentUser } = this.req; - const { card } = await sails.helpers.cards + const { card, board } = await sails.helpers.cards .getProjectPath(inputs.cardId) .intercept('pathNotFound', () => Errors.CARD_NOT_FOUND); @@ -63,6 +63,7 @@ module.exports = { ...values, card, }, + board, request: this.req, }); diff --git a/server/api/helpers/actions/create-one.js b/server/api/helpers/actions/create-one.js index b03adfdc1..e0310c825 100644 --- a/server/api/helpers/actions/create-one.js +++ b/server/api/helpers/actions/create-one.js @@ -95,6 +95,15 @@ module.exports = { buildAndSendSlackMessage(values.user, values.card, action); } + await sails.helpers.utils.sendWebhook.with({ + event: 'ACTION_CREATE', + data: action, + projectId: inputs.board.projectId, + user: inputs.request.currentUser, + card: values.card, + board: inputs.board, + }); + return action; }, }; diff --git a/server/api/helpers/actions/delete-one.js b/server/api/helpers/actions/delete-one.js index 6b9359732..ba862f85b 100644 --- a/server/api/helpers/actions/delete-one.js +++ b/server/api/helpers/actions/delete-one.js @@ -4,6 +4,10 @@ module.exports = { type: 'ref', required: true, }, + card: { + type: 'ref', + required: true, + }, board: { type: 'ref', required: true, @@ -25,6 +29,15 @@ module.exports = { }, inputs.request, ); + + await sails.helpers.utils.sendWebhook.with({ + event: 'ACTION_DELETE', + data: action, + projectId: inputs.board.projectId, + user: inputs.request.currentUser, + card: inputs.card, + board: inputs.board, + }); } return action; diff --git a/server/api/helpers/actions/update-one.js b/server/api/helpers/actions/update-one.js index 47d2f52e9..cdca79c0c 100644 --- a/server/api/helpers/actions/update-one.js +++ b/server/api/helpers/actions/update-one.js @@ -8,6 +8,10 @@ module.exports = { type: 'json', required: true, }, + card: { + type: 'ref', + required: true, + }, board: { type: 'ref', required: true, @@ -31,6 +35,15 @@ module.exports = { }, inputs.request, ); + + await sails.helpers.utils.sendWebhook.with({ + event: 'ACTION_UPDATE', + data: action, + projectId: inputs.board.projectId, + user: inputs.request.currentUser, + card: inputs.card, + board: inputs.board, + }); } return action; diff --git a/server/api/helpers/attachments/create-one.js b/server/api/helpers/attachments/create-one.js index 6ed6e6b79..0a5923b37 100644 --- a/server/api/helpers/attachments/create-one.js +++ b/server/api/helpers/attachments/create-one.js @@ -21,6 +21,10 @@ module.exports = { custom: valuesValidator, required: true, }, + board: { + type: 'ref', + required: true, + }, requestId: { type: 'string', isNotEmptyString: true, @@ -31,7 +35,7 @@ module.exports = { }, async fn(inputs) { - const { values } = inputs; + const { values, board } = inputs; const attachment = await Attachment.create({ ...values, @@ -55,9 +59,20 @@ module.exports = { values: { coverAttachmentId: attachment.id, }, + board, + request: inputs.request, }); } + await sails.helpers.utils.sendWebhook.with({ + event: 'ATTACHMENT_CREATE', + data: attachment, + projectId: board.projectId, + user: inputs.request.currentUser, + card: values.card, + board, + }); + return attachment; }, }; diff --git a/server/api/helpers/attachments/delete-one.js b/server/api/helpers/attachments/delete-one.js index 2f199b457..469e1461f 100644 --- a/server/api/helpers/attachments/delete-one.js +++ b/server/api/helpers/attachments/delete-one.js @@ -48,6 +48,15 @@ module.exports = { }, inputs.request, ); + + await sails.helpers.utils.sendWebhook.with({ + event: 'ATTACHMENT_DELETE', + data: attachment, + projectId: inputs.board.projectId, + user: inputs.request.currentUser, + card: inputs.card, + board: inputs.board, + }); } return attachment; diff --git a/server/api/helpers/attachments/update-one.js b/server/api/helpers/attachments/update-one.js index ba9dd24fa..9de735e17 100644 --- a/server/api/helpers/attachments/update-one.js +++ b/server/api/helpers/attachments/update-one.js @@ -31,6 +31,14 @@ module.exports = { }, inputs.request, ); + + await sails.helpers.utils.sendWebhook.with({ + event: 'ATTACHMENT_UPDATE', + data: attachment, + projectId: inputs.board.projectId, + user: inputs.request.currentUser, + board: inputs.board, + }); } return attachment; diff --git a/server/api/helpers/boards/create-one.js b/server/api/helpers/boards/create-one.js index f9a43c43a..986187222 100644 --- a/server/api/helpers/boards/create-one.js +++ b/server/api/helpers/boards/create-one.js @@ -111,6 +111,14 @@ module.exports = { ); }); + await sails.helpers.utils.sendWebhook.with({ + event: 'BOARD_CREATE', + data: board, + projectId: board.projectId, + user: inputs.request.currentUser, + board, + }); + return { board, boardMembership, diff --git a/server/api/helpers/boards/delete-one.js b/server/api/helpers/boards/delete-one.js index 4fdcc1144..ddc51d7e7 100644 --- a/server/api/helpers/boards/delete-one.js +++ b/server/api/helpers/boards/delete-one.js @@ -35,6 +35,14 @@ module.exports = { }); } + await sails.helpers.utils.sendWebhook.with({ + event: 'BOARD_DELETE', + data: board, + projectId: board.projectId, + user: inputs.request.currentUser, + board, + }); + return board; }, }; diff --git a/server/api/helpers/boards/update-one.js b/server/api/helpers/boards/update-one.js index 9b26733c5..82fdcce0a 100644 --- a/server/api/helpers/boards/update-one.js +++ b/server/api/helpers/boards/update-one.js @@ -83,6 +83,14 @@ module.exports = { }); } + await sails.helpers.utils.sendWebhook.with({ + event: 'BOARD_UPDATE', + data: board, + projectId: board.projectId, + user: inputs.request.currentUser, + board, + }); + return board; }, }; diff --git a/server/api/helpers/card-memberships/create-one.js b/server/api/helpers/card-memberships/create-one.js index bb92b9fd0..52f178826 100644 --- a/server/api/helpers/card-memberships/create-one.js +++ b/server/api/helpers/card-memberships/create-one.js @@ -21,6 +21,10 @@ module.exports = { custom: valuesValidator, required: true, }, + board: { + type: 'ref', + required: true, + }, request: { type: 'ref', }, @@ -75,6 +79,15 @@ module.exports = { ); } + await sails.helpers.utils.sendWebhook.with({ + event: 'CARD_MEMBERSHIP_CREATE', + data: cardMembership, + projectId: inputs.board.projectId, + user: inputs.request.currentUser, + card: values.card, + board: inputs.board, + }); + return cardMembership; }, }; diff --git a/server/api/helpers/card-memberships/delete-one.js b/server/api/helpers/card-memberships/delete-one.js index 5ff6254bf..a4ed107f0 100644 --- a/server/api/helpers/card-memberships/delete-one.js +++ b/server/api/helpers/card-memberships/delete-one.js @@ -4,6 +4,10 @@ module.exports = { type: 'ref', required: true, }, + card: { + type: 'ref', + required: true, + }, board: { type: 'ref', required: true, @@ -40,6 +44,15 @@ module.exports = { }, }); } + + await sails.helpers.utils.sendWebhook.with({ + event: 'CARD_MEMBERSHIP_DELETE', + data: cardMembership, + projectId: inputs.board.projectId, + user: inputs.request.currentUser, + card: inputs.card, + board: inputs.board, + }); } return cardMembership; diff --git a/server/api/helpers/cards/create-one.js b/server/api/helpers/cards/create-one.js index 847a00ca0..0514bf5fe 100644 --- a/server/api/helpers/cards/create-one.js +++ b/server/api/helpers/cards/create-one.js @@ -109,6 +109,17 @@ module.exports = { user: values.creatorUser, }, board: inputs.board, + request: inputs.request, + }); + + await sails.helpers.utils.sendWebhook.with({ + event: 'CARD_CREATE', + data: card, + projectId: inputs.board.projectId, + user: inputs.request.currentUser, + card, + board: inputs.board, + list: values.list, }); return card; diff --git a/server/api/helpers/cards/delete-one.js b/server/api/helpers/cards/delete-one.js index a947f7389..e95596e83 100644 --- a/server/api/helpers/cards/delete-one.js +++ b/server/api/helpers/cards/delete-one.js @@ -21,6 +21,10 @@ module.exports = { const card = await Card.archiveOne(inputs.record.id); if (card) { + const { board } = await sails.helpers.lists + .getProjectPath(card.listId) + .intercept('pathNotFound', () => Errors.LIST_NOT_FOUND); + sails.sockets.broadcast( `board:${card.boardId}`, 'cardDelete', @@ -33,6 +37,15 @@ module.exports = { if (sails.config.custom.slackBotToken) { buildAndSendSlackMessage(inputs.user, card); } + + await sails.helpers.utils.sendWebhook.with({ + event: 'CARD_DELETE', + data: card, + projectId: board.projectId, + user: inputs.request.currentUser, + card, + board, + }); } return card; diff --git a/server/api/helpers/cards/duplicate-one.js b/server/api/helpers/cards/duplicate-one.js index a63feaaca..716455335 100644 --- a/server/api/helpers/cards/duplicate-one.js +++ b/server/api/helpers/cards/duplicate-one.js @@ -132,6 +132,17 @@ module.exports = { user: values.creatorUser, }, board: inputs.board, + request: inputs.request, + }); + + await sails.helpers.utils.sendWebhook.with({ + event: 'CARD_CREATE', + data: card, + projectId: inputs.board.projectId, + user: inputs.request.currentUser, + card, + board: inputs.board, + list: inputs.list, }); return { diff --git a/server/api/helpers/cards/update-one.js b/server/api/helpers/cards/update-one.js index 4363f9b84..cc0540395 100644 --- a/server/api/helpers/cards/update-one.js +++ b/server/api/helpers/cards/update-one.js @@ -233,6 +233,7 @@ module.exports = { }, }, board: inputs.board, + request: inputs.request, }); } @@ -269,6 +270,15 @@ module.exports = { } } + await sails.helpers.utils.sendWebhook.with({ + event: 'CARD_UPDATE', + data: card, + projectId: inputs.board.projectId, + user: inputs.request.currentUser, + card, + board: inputs.board, + }); + return card; }, }; diff --git a/server/api/helpers/lists/create-one.js b/server/api/helpers/lists/create-one.js index 95c258b3e..1c65fcced 100644 --- a/server/api/helpers/lists/create-one.js +++ b/server/api/helpers/lists/create-one.js @@ -67,6 +67,14 @@ module.exports = { inputs.request, ); + await sails.helpers.utils.sendWebhook.with({ + event: 'LIST_CREATE', + data: list, + projectId: values.board.projectId, + user: inputs.request.currentUser, + board: values.board, + }); + return list; }, }; diff --git a/server/api/helpers/lists/delete-one.js b/server/api/helpers/lists/delete-one.js index 47eb7647b..d4f7c49b1 100644 --- a/server/api/helpers/lists/delete-one.js +++ b/server/api/helpers/lists/delete-one.js @@ -4,6 +4,10 @@ module.exports = { type: 'ref', required: true, }, + board: { + type: 'ref', + required: true, + }, request: { type: 'ref', }, @@ -21,6 +25,14 @@ module.exports = { }, inputs.request, ); + + await sails.helpers.utils.sendWebhook.with({ + event: 'LIST_DELETE', + data: list, + projectId: inputs.board.projectId, + user: inputs.request.currentUser, + board: inputs.board, + }); } return list; diff --git a/server/api/helpers/lists/update-one.js b/server/api/helpers/lists/update-one.js index 6b2b0e8f7..ba186b825 100644 --- a/server/api/helpers/lists/update-one.js +++ b/server/api/helpers/lists/update-one.js @@ -21,6 +21,10 @@ module.exports = { custom: valuesValidator, required: true, }, + board: { + type: 'ref', + required: true, + }, request: { type: 'ref', }, @@ -67,6 +71,14 @@ module.exports = { }, inputs.request, ); + + await sails.helpers.utils.sendWebhook.with({ + event: 'LIST_UPDATE', + data: list, + projectId: inputs.board.projectId, + user: inputs.request.currentUser, + board: inputs.board, + }); } return list; diff --git a/server/api/helpers/projects/create-one.js b/server/api/helpers/projects/create-one.js index fb97f007a..7deb9c4a2 100644 --- a/server/api/helpers/projects/create-one.js +++ b/server/api/helpers/projects/create-one.js @@ -32,6 +32,13 @@ module.exports = { inputs.request, ); + await sails.helpers.utils.sendWebhook.with({ + event: 'PROJECT_CREATE', + data: project, + projectId: project.id, + user: inputs.request.currentUser, + }); + return { project, projectManager, diff --git a/server/api/helpers/projects/delete-one.js b/server/api/helpers/projects/delete-one.js index 3328f2f02..1021d2720 100644 --- a/server/api/helpers/projects/delete-one.js +++ b/server/api/helpers/projects/delete-one.js @@ -37,6 +37,13 @@ module.exports = { inputs.request, ); }); + + await sails.helpers.utils.sendWebhook.with({ + event: 'PROJECT_DELETE', + data: project, + projectId: project.id, + user: inputs.request.currentUser, + }); } return project; diff --git a/server/api/helpers/projects/update-one.js b/server/api/helpers/projects/update-one.js index 71e095f19..6b57a71ca 100644 --- a/server/api/helpers/projects/update-one.js +++ b/server/api/helpers/projects/update-one.js @@ -108,6 +108,13 @@ module.exports = { inputs.request, ); }); + + await sails.helpers.utils.sendWebhook.with({ + event: 'PROJECT_UPDATE', + data: project, + projectId: project.id, + user: inputs.request.currentUser, + }); } return project; diff --git a/server/api/helpers/tasks/create-one.js b/server/api/helpers/tasks/create-one.js index c42b00779..7bb331827 100644 --- a/server/api/helpers/tasks/create-one.js +++ b/server/api/helpers/tasks/create-one.js @@ -21,6 +21,10 @@ module.exports = { custom: valuesValidator, required: true, }, + board: { + type: 'ref', + required: true, + }, request: { type: 'ref', }, @@ -67,6 +71,15 @@ module.exports = { inputs.request, ); + await sails.helpers.utils.sendWebhook.with({ + event: 'TASK_CREATE', + data: task, + projectId: inputs.board.projectId, + user: inputs.request.currentUser, + card: values.card, + board: inputs.board, + }); + return task; }, }; diff --git a/server/api/helpers/tasks/delete-one.js b/server/api/helpers/tasks/delete-one.js index f32e5a907..3b876aead 100644 --- a/server/api/helpers/tasks/delete-one.js +++ b/server/api/helpers/tasks/delete-one.js @@ -25,6 +25,14 @@ module.exports = { }, inputs.request, ); + + await sails.helpers.utils.sendWebhook.with({ + event: 'TASK_DELETE', + data: task, + projectId: inputs.board.projectId, + user: inputs.request.currentUser, + board: inputs.board, + }); } return task; diff --git a/server/api/helpers/tasks/update-one.js b/server/api/helpers/tasks/update-one.js index 69958afdd..6d6b81bac 100644 --- a/server/api/helpers/tasks/update-one.js +++ b/server/api/helpers/tasks/update-one.js @@ -71,6 +71,15 @@ module.exports = { }, inputs.request, ); + + await sails.helpers.utils.sendWebhook.with({ + event: 'TASK_UPDATE', + data: task, + projectId: inputs.board.projectId, + user: inputs.request.currentUser, + card: values.card, + board: inputs.board, + }); } return task; diff --git a/server/api/helpers/users/create-one.js b/server/api/helpers/users/create-one.js index ddd07b944..87f36863d 100644 --- a/server/api/helpers/users/create-one.js +++ b/server/api/helpers/users/create-one.js @@ -84,6 +84,23 @@ module.exports = { ); }); + /* The user could be created manually by an user or via OIDC. We hijack the id field, so one can differentiate between the two on the webhook side. */ + let initiator; + if (inputs.request && inputs.request.currentUser) { + initiator = inputs.request.currentUser; + } else { + initiator = { + id: 'oidc', + }; + } + + await sails.helpers.utils.sendWebhook.with({ + event: 'USER_CREATE', + data: { ...user, password: undefined }, + projectId: '', + user: initiator, + }); + return user; }, }; diff --git a/server/api/helpers/users/delete-one.js b/server/api/helpers/users/delete-one.js index 6e2e6a587..524db4b5c 100644 --- a/server/api/helpers/users/delete-one.js +++ b/server/api/helpers/users/delete-one.js @@ -59,6 +59,13 @@ module.exports = { inputs.request, ); }); + + await sails.helpers.utils.sendWebhook.with({ + event: 'USER_DELETE', + data: { ...user, password: undefined }, + projectId: '', + user: inputs.request.currentUser, + }); } return user; diff --git a/server/api/helpers/users/update-one.js b/server/api/helpers/users/update-one.js index 553cdf54c..a829b43e9 100644 --- a/server/api/helpers/users/update-one.js +++ b/server/api/helpers/users/update-one.js @@ -154,6 +154,13 @@ module.exports = { ); }); } + + await sails.helpers.utils.sendWebhook.with({ + event: 'USER_UPDATE', + data: { ...user, password: undefined }, + projectId: '', + user: inputs.request.currentUser, + }); } return user; diff --git a/server/api/helpers/utils/send-webhook.js b/server/api/helpers/utils/send-webhook.js new file mode 100644 index 000000000..a33f7a897 --- /dev/null +++ b/server/api/helpers/utils/send-webhook.js @@ -0,0 +1,115 @@ +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} + */ +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); + } + }, +}; diff --git a/server/config/custom.js b/server/config/custom.js index 9b5484b11..8e335c50b 100644 --- a/server/config/custom.js +++ b/server/config/custom.js @@ -62,4 +62,7 @@ module.exports.custom = { slackBotToken: process.env.SLACK_BOT_TOKEN, slackChannelId: process.env.SLACK_CHANNEL_ID, + + webhookUrl: process.env.WEBHOOK_URL, + webhookBearer: process.env.WEBHOOK_BEARER, };