2
0

slack.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import urljoin from 'url-join';
  2. import loggerFactory from '~/utils/logger';
  3. const logger = loggerFactory('growi:util:slack');
  4. /**
  5. * slack
  6. */
  7. /* eslint-disable no-use-before-define */
  8. const convertMarkdownToMarkdown = (body, siteUrl) =>
  9. body
  10. .replace(/\n\*\s(.+)/g, '\n• $1')
  11. .replace(/#{1,}\s?(.+)/g, '\n*$1*')
  12. .replace(/(\[(.+)\]\((https?:\/\/.+)\))/g, '<$3|$2>')
  13. .replace(/(\[(.+)\]\((\/.+)\))/g, `<${siteUrl}$3|$2>`);
  14. const prepareAttachmentTextForCreate = (page, siteUrl) => {
  15. let body = page.revision.body;
  16. if (body.length > 2000) {
  17. body = `${body.substr(0, 2000)}...`;
  18. }
  19. return convertMarkdownToMarkdown(body, siteUrl);
  20. };
  21. /**
  22. * Return diff with latest revisionBody
  23. * @param {IPageHasId} page
  24. * @param {string} siteUrl
  25. * @param {IRevisionHasId} previousRevision
  26. */
  27. const prepareAttachmentTextForUpdate = (page, siteUrl, previousRevision) => {
  28. if (previousRevision == null) {
  29. return;
  30. }
  31. const diff = require('diff');
  32. let diffText = '';
  33. diff.diffLines(previousRevision.body, page.revision.body).forEach((line) => {
  34. logger.debug('diff line', line);
  35. if (line.added) {
  36. diffText += `${line.value} ... :lower_left_fountain_pen:`;
  37. } else if (line.removed) {
  38. // diffText += '-' + line.value.replace(/(.+)?\n/g, '- $1\n');
  39. // 1以下は無視
  40. if (line.count > 1) {
  41. diffText += `:wastebasket: ... ${line.count} lines\n`;
  42. }
  43. } else {
  44. // diffText += '...\n';
  45. }
  46. });
  47. logger.debug('diff is', diffText);
  48. return diffText;
  49. };
  50. const prepareAttachmentTextForComment = (comment) => {
  51. let body = comment.comment;
  52. if (body.length > 2000) {
  53. body = `${body.substr(0, 2000)}...`;
  54. }
  55. if (comment.isMarkdown) {
  56. return convertMarkdownToMarkdown(body);
  57. }
  58. return body;
  59. };
  60. const generateSlackMessageTextForPage = (
  61. path,
  62. pageId,
  63. user,
  64. siteUrl,
  65. updateType,
  66. ) => {
  67. let text;
  68. const pageUrl = `<${urljoin(siteUrl, pageId)}|${path}>`;
  69. if (updateType === 'create') {
  70. text = `:rocket: ${user.username} created a new page! ${pageUrl}`;
  71. } else {
  72. text = `:heavy_check_mark: ${user.username} updated ${pageUrl}`;
  73. }
  74. return text;
  75. };
  76. export const prepareSlackMessageForPage = (
  77. page,
  78. user,
  79. appTitle,
  80. siteUrl,
  81. channel,
  82. updateType,
  83. previousRevision,
  84. ) => {
  85. let body = page.revision.body;
  86. if (updateType === 'create') {
  87. body = prepareAttachmentTextForCreate(page, siteUrl);
  88. } else {
  89. body = prepareAttachmentTextForUpdate(page, siteUrl, previousRevision);
  90. }
  91. const attachment = {
  92. color: '#263a3c',
  93. author_name: `@${user.username}`,
  94. author_link: urljoin(siteUrl, 'user', user.username),
  95. author_icon: user.image,
  96. title: page.path,
  97. title_link: urljoin(siteUrl, page.id),
  98. text: body,
  99. mrkdwn_in: ['text'],
  100. };
  101. if (user.image) {
  102. attachment.author_icon = user.image;
  103. }
  104. const message = {
  105. channel: channel != null ? `#${channel}` : undefined,
  106. username: appTitle,
  107. text: generateSlackMessageTextForPage(
  108. page.path,
  109. page.id,
  110. user,
  111. siteUrl,
  112. updateType,
  113. ),
  114. attachments: [attachment],
  115. };
  116. return message;
  117. };
  118. export const prepareSlackMessageForComment = (
  119. comment,
  120. user,
  121. appTitle,
  122. siteUrl,
  123. channel,
  124. path,
  125. ) => {
  126. const body = prepareAttachmentTextForComment(comment);
  127. const attachment = {
  128. color: '#263a3c',
  129. author_name: `@${user.username}`,
  130. author_link: urljoin(siteUrl, 'user', user.username),
  131. author_icon: user.image,
  132. text: body,
  133. mrkdwn_in: ['text'],
  134. };
  135. if (user.image) {
  136. attachment.author_icon = user.image;
  137. }
  138. const pageUrl = `<${urljoin(siteUrl, String(comment.page))}|${path}>`;
  139. const text = `:speech_balloon: ${user.username} commented on ${pageUrl}`;
  140. const message = {
  141. channel: channel != null ? `#${channel}` : undefined,
  142. username: appTitle,
  143. text,
  144. attachments: [attachment],
  145. };
  146. return message;
  147. };
  148. /**
  149. * For GlobalNotification
  150. *
  151. * @param {string} messageBody
  152. * @param {string} attachmentBody
  153. * @param {string} slackChannel
  154. */
  155. export const prepareSlackMessageForGlobalNotification = (
  156. messageBody,
  157. attachmentBody,
  158. appTitle,
  159. slackChannel,
  160. ) => {
  161. const attachment = {
  162. color: '#263a3c',
  163. text: attachmentBody,
  164. mrkdwn_in: ['text'],
  165. };
  166. const message = {
  167. channel: slackChannel != null ? `#${slackChannel}` : undefined,
  168. username: appTitle,
  169. text: messageBody,
  170. attachments: JSON.stringify([attachment]),
  171. };
  172. return message;
  173. };