Ghost/core/server/data/slack/index.js
Aileen Nowak 35ecaee6d3 Slack integration
closes #6584
- Frontend Changes:
	- adds 'Apps' to Navigation Menu
	- adds 'Slack' as nested page to Apps
	- adds `apps.css`
	- adds `slack-integration` model and uses `slack-settings` custom transform to parse JSON file
	- adds validation for `slack` model
	- adds fixtures and `slack/test` API endpoint to Mirage
	- adds acceptance tests for `apps-test` and `slack-test`
	- adds unit tests for `slack-settings` and `slack-integration`
- Backend Changes:
	- adds API endpoint `slack/test` to send Test Notification
	- adds default-values for slack model
	- sends payload to slack:
		- text: the url of the blogpost / test message
		- icon_url: url to ghost logo
		- username: Ghost
	- adds `slack/index.js` to send webhook to slack if
		- a new post is published (if slack webhook url is saved in settings)
		- user clicks on 'Send Test Notification' in UI
	- adds `slack.init()` to `server.index.js` to add event listener
	- adds unit test for `slack/index`
2016-05-08 12:49:15 +02:00

107 lines
3.1 KiB
JavaScript

var https = require('https'),
errors = require('../../errors'),
url = require('url'),
Promise = require('bluebird'),
config = require('../../config'),
events = require('../../events'),
api = require('../../api/settings'),
i18n = require('../../i18n'),
schema = require('../schema').checks,
options,
req,
slack = {},
slackData = {};
function getSlackSettings() {
return api.read({context: {internal: true}, key: 'slack'}).then(function (response) {
var slackSetting = response.settings[0].value;
try {
slackSetting = JSON.parse(slackSetting) || slackSetting;
} catch (e) {
return Promise.reject(e);
}
return slackSetting[0];
});
}
function makeRequest(reqOptions, reqPayload) {
req = https.request(reqOptions);
reqPayload = JSON.stringify(reqPayload);
req.write(reqPayload);
req.on('error', function (error) {
errors.logError(
error,
i18n.t('errors.data.xml.xmlrpc.pingUpdateFailed.error'),
i18n.t('errors.data.xml.xmlrpc.pingUpdateFailed.help', {url: 'http://support.ghost.org'})
);
});
req.end();
}
function ping(post) {
var message;
// If this is a post, we want to send the link of the post
if (schema.isPost(post)) {
message = config.urlFor('post', {post: post}, true);
} else {
message = post.message;
}
return getSlackSettings().then(function (slackSettings) {
// Quit here if slack integration is not activated
if (slackSettings.url && slackSettings.url !== '') {
// Only ping when not a page
if (post.page) {
return;
}
// Don't ping for the welcome to ghost post.
// This also handles the case where during ghost's first run
// models.init() inserts this post but permissions.init() hasn't
// (can't) run yet.
if (post.slug === 'welcome-to-ghost') {
return;
}
slackData = {
text: message,
unfurl_links: true,
icon_url: config.urlFor({relativeUrl: '/ghost/img/ghosticon.jpg'}, {}, true),
username: 'Ghost'
};
// fill the options for https request
options = url.parse(slackSettings.url);
options.method = 'POST';
options.headers = {'Content-type': 'application/json'};
// with all the data we have, we're doing the request now
slack._makeRequest(options, slackData);
} else {
return;
}
});
}
function init() {
events.on('post.published', function (model) {
slack._ping(model.toJSON());
});
events.on('slack.test', function () {
slack._ping({
message: 'Heya! This is a test notification from your Ghost blog :simple_smile:. Seems to work fine!'
});
});
}
slack.init = init;
slack._ping = ping;
slack._makeRequest = makeRequest;
module.exports = slack;