bolt.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. const logger = require('@alias/logger')('growi:service:BoltService');
  2. class BoltReciever {
  3. init(app) {
  4. this.bolt = app;
  5. }
  6. async requestHandler(req, res) {
  7. let ackCalled = false;
  8. // for verification request URL on Event Subscriptions
  9. if (req.body.challenge && req.body.type) {
  10. return res.send(req.body);
  11. }
  12. const event = {
  13. body: req.body,
  14. ack: (response) => {
  15. if (ackCalled) {
  16. return;
  17. }
  18. if (response instanceof Error) {
  19. res.status(500).send();
  20. }
  21. else if (!response) {
  22. res.send('');
  23. }
  24. else {
  25. res.send(response);
  26. }
  27. ackCalled = true;
  28. },
  29. };
  30. await this.bolt.processEvent(event);
  31. }
  32. }
  33. const { App } = require('@slack/bolt');
  34. const { WebClient, LogLevel } = require('@slack/web-api');
  35. class BoltService {
  36. constructor(crowi) {
  37. this.crowi = crowi;
  38. this.receiver = new BoltReciever();
  39. const signingSecret = crowi.configManager.getConfig('crowi', 'slackbot:signingSecret');
  40. const token = crowi.configManager.getConfig('crowi', 'slackbot:token');
  41. const client = new WebClient(token, { logLevel: LogLevel.DEBUG });
  42. this.client = client;
  43. if (token != null || signingSecret != null) {
  44. logger.debug('TwitterStrategy: setup is done');
  45. this.bolt = new App({
  46. token,
  47. signingSecret,
  48. receiver: this.receiver,
  49. });
  50. this.init();
  51. }
  52. }
  53. init() {
  54. // Example of listening for event
  55. // See. https://github.com/slackapi/bolt-js#listening-for-events
  56. // or https://slack.dev/bolt-js/concepts#basic
  57. this.bolt.command('/growi-bot', async({ command, ack, say }) => { // demo
  58. await say('Hello');
  59. });
  60. // The echo command simply echoes on command
  61. this.bolt.command('/echo', async({ command, ack, say }) => {
  62. // Acknowledge command request
  63. await ack();
  64. await say(`${command.text}`);
  65. });
  66. this.bolt.command('/growi', async({ command, ack }) => {
  67. await ack();
  68. const args = command.text.split(' ');
  69. const firstArg = args[0];
  70. switch (firstArg) {
  71. case 'search':
  72. this.searchResults(command, args);
  73. break;
  74. default:
  75. this.notCommand(command);
  76. break;
  77. }
  78. });
  79. }
  80. notCommand(command) {
  81. logger.error('Input first arguments');
  82. return this.client.chat.postEphemeral({
  83. channel: command.channel_id,
  84. user: command.user_id,
  85. blocks: [
  86. this.generateMarkdownSectionBlock('*コマンドが存在しません。*\n Hint\n `/growi [command] [keyword]`'),
  87. ],
  88. });
  89. }
  90. async searchResults(command, args) {
  91. const firstKeyword = args[1];
  92. if (firstKeyword == null) {
  93. return this.client.chat.postEphemeral({
  94. channel: command.channel_id,
  95. user: command.user_id,
  96. blocks: [
  97. this.generateMarkdownSectionBlock('*キーワードを入力してください。*\n Hint\n `/growi search [keyword]`'),
  98. ],
  99. });
  100. }
  101. // remove leading 'search'.
  102. args.shift();
  103. const keywords = args.join(' ');
  104. const { searchService } = this.crowi;
  105. const option = { limit: 10 };
  106. const results = await searchService.searchKeyword(keywords, null, {}, option);
  107. // no search results
  108. if (results.data.length === 0) {
  109. return this.client.chat.postEphemeral({
  110. channel: command.channel_id,
  111. user: command.user_id,
  112. blocks: [
  113. this.generateMarkdownSectionBlock('*キーワードに該当するページは存在しません。*'),
  114. ],
  115. });
  116. }
  117. const resultPaths = results.data.map((data) => {
  118. return data._source.path;
  119. });
  120. try {
  121. await this.client.chat.postEphemeral({
  122. channel: command.channel_id,
  123. user: command.user_id,
  124. blocks: [
  125. this.generateMarkdownSectionBlock('検索結果 10 件'),
  126. this.generateMarkdownSectionBlock(`${resultPaths.join('\n')}`),
  127. ],
  128. });
  129. }
  130. catch {
  131. logger.error('Failed to get search results.');
  132. await this.client.chat.postEphemeral({
  133. channel: command.channel_id,
  134. user: command.user_id,
  135. blocks: [
  136. this.generateMarkdownSectionBlock('*検索に失敗しました。*\n Hint\n `/growi search [keyword]`'),
  137. ],
  138. });
  139. }
  140. }
  141. generateMarkdownSectionBlock(blocks) {
  142. return {
  143. type: 'section',
  144. text: {
  145. type: 'mrkdwn',
  146. text: blocks,
  147. },
  148. };
  149. }
  150. }
  151. module.exports = BoltService;