slack.js 5.0 KB

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