slack.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /**
  2. * slack
  3. */
  4. module.exports = function(crowi) {
  5. 'use strict';
  6. const SLACK_URL = 'https://slack.com';
  7. const debug = require('debug')('crowi:util:slack'),
  8. config = crowi.getConfig(),
  9. Config = crowi.model('Config'),
  10. Slack = require('slack-node'),
  11. slack = {};
  12. const postWithIwh = function(messageObj, callback) {
  13. const client = new Slack();
  14. client.setWebhook(config.notification['slack:incomingWebhookUrl']);
  15. client.webhook(messageObj, callback);
  16. }
  17. const postWithWebApi = function(messageObj, callback) {
  18. const client = new Slack(config.notification['slack:token']);
  19. client.api('chat.postMessage', messageObj, callback);
  20. }
  21. const convertMarkdownToMrkdwn = function(body) {
  22. var url = '';
  23. if (config.crowi && config.crowi['app:url']) {
  24. url = config.crowi['app:url'];
  25. }
  26. body = body
  27. .replace(/\n\*\s(.+)/g, '\n• $1')
  28. .replace(/#{1,}\s?(.+)/g, '\n*$1*')
  29. .replace(/(\[(.+)\]\((https?:\/\/.+)\))/g, '<$3|$2>')
  30. .replace(/(\[(.+)\]\((\/.+)\))/g, '<' + url + '$3|$2>')
  31. ;
  32. return body;
  33. };
  34. const prepareAttachmentTextForCreate = function(page, user) {
  35. var body = page.revision.body;
  36. if (body.length > 2000) {
  37. body = body.substr(0, 2000) + '...';
  38. }
  39. return convertMarkdownToMrkdwn(body);
  40. };
  41. const prepareAttachmentTextForUpdate = function(page, user, previousRevision) {
  42. var diff = require('diff');
  43. var diffText = ''
  44. diff.diffLines(previousRevision.body, page.revision.body).forEach(function(line) {
  45. debug('diff line', line)
  46. var value = line.value.replace(/\r\n|\r/g, '\n');
  47. if (line.added) {
  48. diffText += `:pencil2: ...\n${line.value}`;
  49. } else if (line.removed) {
  50. // diffText += '-' + line.value.replace(/(.+)?\n/g, '- $1\n');
  51. // 1以下は無視
  52. if (line.count > 1) {
  53. diffText += `:wastebasket: ... ${line.count} lines\n`;
  54. }
  55. } else {
  56. //diffText += '...\n';
  57. }
  58. });
  59. debug('diff is', diffText)
  60. return diffText;
  61. };
  62. const prepareSlackMessage = function(page, user, channel, updateType, previousRevision) {
  63. var url = config.crowi['app:url'] || '';
  64. var body = page.revision.body;
  65. if (updateType == 'create') {
  66. body = prepareAttachmentTextForCreate(page, user);
  67. } else {
  68. body = prepareAttachmentTextForUpdate(page, user, previousRevision);
  69. }
  70. var attachment = {
  71. color: '#263a3c',
  72. author_name: '@' + user.username,
  73. author_link: url + '/user/' + user.username,
  74. author_icon: user.image,
  75. title: page.path,
  76. title_link: url + '/' + page._id,
  77. text: body,
  78. mrkdwn_in: ["text"],
  79. };
  80. if (user.image) {
  81. attachment.author_icon = user.image;
  82. }
  83. var message = {
  84. channel: '#' + channel,
  85. username: Config.appTitle(config),
  86. text: getSlackMessageText(page.path, user, updateType),
  87. attachments: [attachment],
  88. };
  89. return message;
  90. };
  91. const getSlackMessageText = function(path, user, updateType) {
  92. let text;
  93. const url = config.crowi['app:url'] || '';
  94. const pageUrl = `<${url}${path}|${path}>`;
  95. if (updateType == 'create') {
  96. text = `:white_check_mark: ${user.username} created a new page! ${pageUrl}`;
  97. } else {
  98. text = `:up: ${user.username} updated ${pageUrl}`;
  99. }
  100. return text;
  101. };
  102. // this is called to generate redirect_uri
  103. slack.getSlackAuthCallbackUrl = function()
  104. {
  105. // Web アクセスがきてないと app:url がセットされないので crowi.setupSlack 時にはできない
  106. // cli, bot 系作るときに問題なりそう
  107. return (config.crowi['app:url'] || '') + '/admin/notification/slackAuth';
  108. }
  109. // this is called to get the url for oauth screen
  110. slack.getAuthorizeURL = function () {
  111. if (Config.hasSlackWebClientConfig(config)) {
  112. const slackClientId = config.notification['slack:clientId'];
  113. const redirectUri = slack.getSlackAuthCallbackUrl();
  114. return `${SLACK_URL}/oauth/authorize?client_id=${slackClientId}&redirect_uri=${redirectUri}&scope=chat:write:bot`;
  115. } else {
  116. return '';
  117. }
  118. }
  119. // this is called to get access token with code (oauth process)
  120. slack.getOauthAccessToken = function(code) {
  121. const client = new SlackWebClient();
  122. const clientId = config.notification['slack:clientId'];
  123. const clientSecret = config.notification['slack:clientSecret'];
  124. const redirectUri = slack.getSlackAuthCallbackUrl();
  125. return client.oauth.access(clientId, clientSecret, code, {redirect_uri: redirectUri});
  126. }
  127. // slack.post = function (channel, message, opts) {
  128. slack.post = (page, user, channel, updateType, previousRevision) => {
  129. const messageObj = prepareSlackMessage(page, user, channel, updateType, previousRevision);
  130. return new Promise((resolve, reject) => {
  131. // define callback function for Promise
  132. const callback = function(err, res) {
  133. if (err) {
  134. debug('Post error', err, res);
  135. debug('Sent data to slack is:', messageObj);
  136. return reject(err);
  137. }
  138. resolve(res);
  139. };
  140. // when incoming Webhooks is prioritized
  141. if (Config.isIncomingWebhookPrioritized(config)) {
  142. if (Config.hasSlackIwhUrl(config)) {
  143. debug(`posting message with IncomingWebhook`);
  144. postWithIwh(messageObj, callback);
  145. }
  146. else if (Config.hasSlackToken(config)) {
  147. debug(`posting message with Web API`);
  148. postWithWebApi(messageObj, callback);
  149. }
  150. }
  151. // else
  152. else {
  153. if (Config.hasSlackToken(config)) {
  154. debug(`posting message with Web API`);
  155. postWithWebApi(messageObj, callback);
  156. }
  157. else if (Config.hasSlackIwhUrl(config)) {
  158. debug(`posting message with IncomingWebhook`);
  159. postWithIwh(messageObj, callback);
  160. }
  161. }
  162. resolve();
  163. });
  164. };
  165. return slack;
  166. };