From 95580f5ffe4d0796f7f886e8757074fe04e73d47 Mon Sep 17 00:00:00 2001 From: Vicky Chijwani Date: Thu, 5 Oct 2017 05:32:37 +0530 Subject: [PATCH 1/2] Add Slack notifications plugin for new comments. --- .gitignore | 1 + .../.eslintrc.json | 3 ++ .../talk-plugin-slack-notifications/index.js | 5 +++ .../package.json | 9 ++++ .../server/config.js | 11 +++++ .../server/hooks.js | 44 +++++++++++++++++++ 6 files changed, 73 insertions(+) create mode 100644 plugins/talk-plugin-slack-notifications/.eslintrc.json create mode 100644 plugins/talk-plugin-slack-notifications/index.js create mode 100644 plugins/talk-plugin-slack-notifications/package.json create mode 100644 plugins/talk-plugin-slack-notifications/server/config.js create mode 100644 plugins/talk-plugin-slack-notifications/server/hooks.js diff --git a/.gitignore b/.gitignore index 9c55f2708..0ab845e4e 100644 --- a/.gitignore +++ b/.gitignore @@ -45,5 +45,6 @@ plugins/* !plugins/talk-plugin-deep-reply-count !plugins/talk-plugin-subscriber !plugins/talk-plugin-flag-details +!plugins/talk-plugin-slack-notifications **/node_modules/* diff --git a/plugins/talk-plugin-slack-notifications/.eslintrc.json b/plugins/talk-plugin-slack-notifications/.eslintrc.json new file mode 100644 index 000000000..78f7c2397 --- /dev/null +++ b/plugins/talk-plugin-slack-notifications/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "@coralproject/eslint-config-talk" +} diff --git a/plugins/talk-plugin-slack-notifications/index.js b/plugins/talk-plugin-slack-notifications/index.js new file mode 100644 index 000000000..1f2a73ff0 --- /dev/null +++ b/plugins/talk-plugin-slack-notifications/index.js @@ -0,0 +1,5 @@ +const hooks = require('./server/hooks'); + +module.exports = { + hooks, +}; diff --git a/plugins/talk-plugin-slack-notifications/package.json b/plugins/talk-plugin-slack-notifications/package.json new file mode 100644 index 000000000..6792e77fa --- /dev/null +++ b/plugins/talk-plugin-slack-notifications/package.json @@ -0,0 +1,9 @@ +{ + "name": "@coralproject/talk-plugin-slack-notifications", + "pluginName": "talk-plugin-slack-notifications", + "version": "0.0.1", + "description": "Posts new comments to Slack via a webhook", + "main": "index.js", + "author": "The Coral Project Team ", + "license": "Apache-2.0" +} diff --git a/plugins/talk-plugin-slack-notifications/server/config.js b/plugins/talk-plugin-slack-notifications/server/config.js new file mode 100644 index 000000000..7571565b0 --- /dev/null +++ b/plugins/talk-plugin-slack-notifications/server/config.js @@ -0,0 +1,11 @@ +const config = { + SLACK_WEBHOOK_URL: process.env.TALK_SLACK_WEBHOOK_URL, + SLACK_WEBHOOK_TIMEOUT: process.env.TALK_SLACK_WEBHOOK_TIMEOUT || 5000, +}; + +if (process.env.NODE_ENV !== 'test' && !config.SLACK_WEBHOOK_URL) { + // TODO this error should point users to Talk's Slack app once that's in place + throw new Error('Please set the TALK_SLACK_WEBHOOK_URL environment variable to use the slack-notifications plugin.'); +} + +module.exports = config; diff --git a/plugins/talk-plugin-slack-notifications/server/hooks.js b/plugins/talk-plugin-slack-notifications/server/hooks.js new file mode 100644 index 000000000..a2f3ca743 --- /dev/null +++ b/plugins/talk-plugin-slack-notifications/server/hooks.js @@ -0,0 +1,44 @@ +const fetch = require('node-fetch'); +const {SLACK_WEBHOOK_URL, SLACK_WEBHOOK_TIMEOUT} = require('./config'); +const debug = require('debug')('talk:plugin:slack-notifications'); + +// We don't add the hooks during _test_ as the Slack API is not available. +if (process.env.NODE_ENV === 'test') { + return null; +} + +module.exports = { + RootMutation: { + createComment: { + async post(_, {input}, context, _info, result) { + debug(`Posting notification to Slack webhook: ${SLACK_WEBHOOK_URL}`); + const { + comment: { + body: text, + created_at: createdAt + } + } = result; + const username = context.user.username; + const response = await fetch(SLACK_WEBHOOK_URL, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + timeout: SLACK_WEBHOOK_TIMEOUT, + body: JSON.stringify({ + attachments: [{ + text: text, + footer: `Comment by ${username}`, + ts: Math.floor(Date.parse(createdAt) / 1000), + }] + }), + }); + if (!response.ok) { + const responseText = await response.text(); + console.trace(`Posting to Slack failed with HTTP code ${response.status} and body '${responseText}'`); + } + return result; + }, + }, + }, +}; From bf0901e77fa7c8fe3d313b3c52d191f2dda35f92 Mon Sep 17 00:00:00 2001 From: Vicky Chijwani Date: Fri, 6 Oct 2017 02:15:28 +0530 Subject: [PATCH 2/2] Wrap Slack call in process.nextTick() to avoid blocking comment creation. --- .../server/hooks.js | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/plugins/talk-plugin-slack-notifications/server/hooks.js b/plugins/talk-plugin-slack-notifications/server/hooks.js index a2f3ca743..bda9dc4f5 100644 --- a/plugins/talk-plugin-slack-notifications/server/hooks.js +++ b/plugins/talk-plugin-slack-notifications/server/hooks.js @@ -19,24 +19,26 @@ module.exports = { } } = result; const username = context.user.username; - const response = await fetch(SLACK_WEBHOOK_URL, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - timeout: SLACK_WEBHOOK_TIMEOUT, - body: JSON.stringify({ - attachments: [{ - text: text, - footer: `Comment by ${username}`, - ts: Math.floor(Date.parse(createdAt) / 1000), - }] - }), + process.nextTick(async () => { + const response = await fetch(SLACK_WEBHOOK_URL, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + timeout: SLACK_WEBHOOK_TIMEOUT, + body: JSON.stringify({ + attachments: [{ + text: text, + footer: `Comment by ${username}`, + ts: Math.floor(Date.parse(createdAt) / 1000), + }] + }), + }); + if (!response.ok) { + const responseText = await response.text(); + console.trace(`Posting to Slack failed with HTTP code ${response.status} and body '${responseText}'`); + } }); - if (!response.ok) { - const responseText = await response.text(); - console.trace(`Posting to Slack failed with HTTP code ${response.status} and body '${responseText}'`); - } return result; }, },