slack.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /**
  2. * slack
  3. */
  4. module.exports = function(crowi) {
  5. 'use strict';
  6. var debug = require('debug')('crowi:util:slack'),
  7. Config = crowi.model('Config'),
  8. Botkit = require('botkit'),
  9. isDebugSlackbot = false,
  10. appBot = null, // for Slack App
  11. iwhBot = null, // for Slack Incoming Webhooks
  12. slack = {};
  13. slack.appController = undefined; // for Slack App
  14. slack.iwhController = undefined; // for Slack Incoming Webhooks
  15. // isDebugSlackbot = true; // for debug
  16. slack.getBot = function() {
  17. var config = crowi.getConfig();
  18. // when incoming Webhooks is prioritized
  19. if (Config.isIncomingWebhookPrioritized(config)) {
  20. if (Config.hasSlackIwhUrl(config)) {
  21. return iwhBot || slack.initIwhBot();
  22. }
  23. else if (Config.hasSlackToken(config)) {
  24. return appBot || slack.initAppBot();
  25. }
  26. }
  27. // else
  28. else {
  29. if (Config.hasSlackToken(config)) {
  30. return appBot || slack.initAppBot();
  31. }
  32. else if (Config.hasSlackIwhUrl(config)) {
  33. return iwhBot || slack.initIwhBot();
  34. }
  35. }
  36. return false;
  37. };
  38. slack.initAppBot = function(isClearToken) {
  39. var config = crowi.getConfig();
  40. if (!slack.appController) {
  41. slack.configureSlackApp();
  42. }
  43. if (!slack.appController) {
  44. return false;
  45. }
  46. if (!isClearToken && Config.hasSlackToken(config)) {
  47. appBot = slack.appController.spawn({token: config.notification['slack:token']});
  48. } else {
  49. appBot = slack.appController.spawn();
  50. }
  51. return appBot;
  52. };
  53. slack.initIwhBot = function() {
  54. var config = crowi.getConfig();
  55. if (!slack.iwhController) {
  56. slack.configureSlackIwh();
  57. }
  58. if (!slack.iwhController) {
  59. return false;
  60. }
  61. iwhBot = slack.iwhController.spawn({
  62. incoming_webhook: {
  63. url: config.notification['slack:incomingWebhookUrl']
  64. }
  65. });
  66. return iwhBot;
  67. }
  68. slack.configureSlackApp = function ()
  69. {
  70. var config = crowi.getConfig();
  71. if (Config.hasSlackAppConfig(config)) {
  72. slack.appController = Botkit.slackbot({debug: isDebugSlackbot});
  73. slack.appController.configureSlackApp({
  74. clientId: config.notification['slack:clientId'],
  75. clientSecret: config.notification['slack:clientSecret'],
  76. redirectUri: slack.getSlackAuthCallbackUrl(),
  77. scopes: ['chat:write:bot']
  78. });
  79. return true;
  80. }
  81. return false;
  82. }
  83. slack.configureSlackIwh = function ()
  84. {
  85. var config = crowi.getConfig();
  86. if (Config.hasSlackIwhUrl(config)) {
  87. slack.iwhController = Botkit.slackbot({debug: isDebugSlackbot});
  88. return true;
  89. }
  90. return false;
  91. }
  92. // hmmm
  93. slack.getSlackAuthCallbackUrl = function()
  94. {
  95. var config = crowi.getConfig();
  96. // Web アクセスがきてないと app:url がセットされないので crowi.setupSlack 時にはできない
  97. // cli, bot 系作るときに問題なりそう
  98. return (config.crowi['app:url'] || '') + '/admin/notification/slackAuth';
  99. }
  100. slack.getAuthorizeURL = function () {
  101. if (!slack.appController) {
  102. slack.configureSlackApp();
  103. }
  104. if (!slack.appController) {
  105. return '';
  106. }
  107. return slack.appController.getAuthorizeURL();
  108. }
  109. slack.post = function (message) {
  110. var bot = slack.getBot();
  111. let sendMethod = undefined;
  112. // use Slack App
  113. if (bot === appBot) {
  114. debug(`sendMethod: bot.api.chat.postMessage`);
  115. sendMethod = bot.api.chat.postMessage;
  116. }
  117. // use Slack Incoming Webhooks
  118. else if (bot === iwhBot) {
  119. debug(`sendMethod: bot.sendWebhook`);
  120. sendMethod = bot.sendWebhook;
  121. }
  122. if (sendMethod === undefined) {
  123. debug(`sendMethod is undefined`);
  124. return Promise.resolve();
  125. }
  126. return new Promise(function(resolve, reject) {
  127. sendMethod(message, function(err, res) {
  128. if (err) {
  129. debug('Post error', err, res);
  130. debug('Sent data to slack is:', message);
  131. return reject(err);
  132. }
  133. resolve(res);
  134. });
  135. });
  136. };
  137. slack.convertMarkdownToMrkdwn = function(body) {
  138. var config = crowi.getConfig();
  139. var url = '';
  140. if (config.crowi && config.crowi['app:url']) {
  141. url = config.crowi['app:url'];
  142. }
  143. body = body
  144. .replace(/\n\*\s(.+)/g, '\n• $1')
  145. .replace(/#{1,}\s?(.+)/g, '\n*$1*')
  146. .replace(/(\[(.+)\]\((https?:\/\/.+)\))/g, '<$3|$2>')
  147. .replace(/(\[(.+)\]\((\/.+)\))/g, '<' + url + '$3|$2>')
  148. ;
  149. return body;
  150. };
  151. slack.prepareAttachmentTextForCreate = function(page, user) {
  152. var body = page.revision.body;
  153. if (body.length > 2000) {
  154. body = body.substr(0, 2000) + '...';
  155. }
  156. return this.convertMarkdownToMrkdwn(body);
  157. };
  158. slack.prepareAttachmentTextForUpdate = function(page, user, previousRevision) {
  159. var diff = require('diff');
  160. var diffText = ''
  161. diff.diffLines(previousRevision.body, page.revision.body).forEach(function(line) {
  162. debug('diff line', line)
  163. var value = line.value.replace(/\r\n|\r/g, '\n');
  164. if (line.added) {
  165. diffText += `:pencil2: ...\n${line.value}`;
  166. } else if (line.removed) {
  167. // diffText += '-' + line.value.replace(/(.+)?\n/g, '- $1\n');
  168. // 1以下は無視
  169. if (line.count > 1) {
  170. diffText += `:wastebasket: ... ${line.count} lines\n`;
  171. }
  172. } else {
  173. //diffText += '...\n';
  174. }
  175. });
  176. debug('diff is', diffText)
  177. return diffText;
  178. };
  179. slack.prepareSlackMessage = function(page, user, channel, updateType, previousRevision) {
  180. var config = crowi.getConfig();
  181. var url = config.crowi['app:url'] || '';
  182. var body = page.revision.body;
  183. if (updateType == 'create') {
  184. body = this.prepareAttachmentTextForCreate(page, user);
  185. } else {
  186. body = this.prepareAttachmentTextForUpdate(page, user, previousRevision);
  187. }
  188. var attachment = {
  189. color: '#263a3c',
  190. author_name: '@' + user.username,
  191. author_link: url + '/user/' + user.username,
  192. author_icon: user.image,
  193. title: page.path,
  194. title_link: url + '/' + page._id,
  195. text: body,
  196. mrkdwn_in: ["text"],
  197. };
  198. if (user.image) {
  199. attachment.author_icon = user.image;
  200. }
  201. var message = {
  202. channel: '#' + channel,
  203. username: 'Crowi',
  204. text: this.getSlackMessageText(page.path, user, updateType),
  205. attachments: [attachment],
  206. };
  207. return message;
  208. };
  209. slack.getSlackMessageText = function(path, user, updateType) {
  210. var text;
  211. if (updateType == 'create') {
  212. text = `:white_check_mark: ${user.username} created a new page! ${path}`;
  213. } else {
  214. text = `:up: ${user.username} updated ${path}`;
  215. }
  216. return text;
  217. };
  218. return slack;
  219. };