slack.js 6.5 KB

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