diff --git a/test/api/v3/unit/libs/webhooks.test.js b/test/api/v3/unit/libs/webhooks.test.js new file mode 100644 index 0000000000..62aeee3922 --- /dev/null +++ b/test/api/v3/unit/libs/webhooks.test.js @@ -0,0 +1,136 @@ +import request from 'request'; +import { sendTaskWebhook } from '../../../../../website/src/libs/api-v3/webhook'; + +describe('webhooks', () => { + + beforeEach(() => { + sandbox.stub(request, 'post'); + }); + + afterEach(() => { + sandbox.restore(); + }); + + describe('sendTaskWebhook', () => { + let task = { + details: { _id: 'task-id' }, + delta: 1.4, + direction: 'up' + }; + + let data = { + task: task, + user: { _id: 'user-id' } + }; + + it('does not send if no webhook endpoints exist', () => { + let webhooks = { }; + + sendTaskWebhook(webhooks, data); + + expect(request.post).to.not.be.called; + }); + + it('does not send if no webhooks are enabled', () => { + let webhooks = { + 'some-id': { + sort: 0, + id: 'some-id', + enabled: false, + url: 'http://example.org/endpoint' + } + }; + + sendTaskWebhook(webhooks, data); + + expect(request.post).to.not.be.called; + }); + + it('does not send if webhook url is not valid', () => { + let webhooks = { + 'some-id': { + sort: 0, + id: 'some-id', + enabled: true, + url: 'http://malformedurl/endpoint' + } + }; + + sendTaskWebhook(webhooks, data); + + expect(request.post).to.not.be.called; + }); + + it('sends task direction, task, task delta, and abridged user data', () => { + let webhooks = { + 'some-id': { + sort: 0, + id: 'some-id', + enabled: true, + url: 'http://example.org/endpoint' + } + }; + + sendTaskWebhook(webhooks, data); + + expect(request.post).to.be.calledOnce; + expect(request.post).to.be.calledWith({ + url: 'http://example.org/endpoint', + body: { + direction: 'up', + task: { _id: 'task-id' }, + delta: 1.4, + user: { + _id: 'user-id' + } + }, + json: true + }); + }); + + it('sends a post request for each webhook endpoint', () => { + let webhooks = { + 'some-id': { + sort: 0, + id: 'some-id', + enabled: true, + url: 'http://example.org/endpoint' + }, + 'second-webhook': { + sort: 1, + id: 'second-webhook', + enabled: true, + url: 'http://example.com/2/endpoint' + } + }; + + sendTaskWebhook(webhooks, data); + + expect(request.post).to.be.calledTwice; + expect(request.post).to.be.calledWith({ + url: 'http://example.org/endpoint', + body: { + direction: 'up', + task: { _id: 'task-id' }, + delta: 1.4, + user: { + _id: 'user-id' + } + }, + json: true + }); + expect(request.post).to.be.calledWith({ + url: 'http://example.com/2/endpoint', + body: { + direction: 'up', + task: { _id: 'task-id' }, + delta: 1.4, + user: { + _id: 'user-id' + } + }, + json: true + }); + }); + }); +}); diff --git a/website/src/controllers/api-v2/user.js b/website/src/controllers/api-v2/user.js index b8d3dd7bf1..ed8aa05f25 100644 --- a/website/src/controllers/api-v2/user.js +++ b/website/src/controllers/api-v2/user.js @@ -16,7 +16,7 @@ var logging = require('./../../libs/api-v2/logging'); var acceptablePUTPaths; var api = module.exports; var firebase = require('../../libs/firebase'); -var webhook = require('../../libs/webhook'); +var webhook = require('../../libs/api-v2/webhook'); // api.purchase // Shared.ops diff --git a/website/src/libs/webhook.js b/website/src/libs/api-v2/webhook.js similarity index 100% rename from website/src/libs/webhook.js rename to website/src/libs/api-v2/webhook.js diff --git a/website/src/libs/api-v3/webhook.js b/website/src/libs/api-v3/webhook.js new file mode 100644 index 0000000000..f1c6f13df2 --- /dev/null +++ b/website/src/libs/api-v3/webhook.js @@ -0,0 +1,30 @@ +import { each } from 'lodash'; +import { post } from 'request'; +import { isURL } from 'validator'; + +let _sendWebhook = (url, body) => { + post({ + url, + body, + json: true, + }); +}; + +let _isInvalidWebhook = (hook) => { + return !hook.enabled || !isURL(hook.url); +}; + +export function sendTaskWebhook (webhooks, data) { + each(webhooks, (hook) => { + if (_isInvalidWebhook(hook)) return; + + let body = { + direction: data.task.direction, + task: data.task.details, + delta: data.task.delta, + user: data.user, + }; + + _sendWebhook(hook.url, body); + }); +}