Просмотр исходного кода

Merge branch 'feat/growi-bot' into 5882-PUT-error

Steven Fukase 5 лет назад
Родитель
Сommit
021840ad1e

+ 1 - 0
packages/slack/package.json

@@ -15,6 +15,7 @@
     "test:lint:fix": "eslint src --ext .ts --fix"
     "test:lint:fix": "eslint src --ext .ts --fix"
   },
   },
   "dependencies": {
   "dependencies": {
+    "axios": "^0.21.1",
     "browser-bunyan": "^1.6.3",
     "browser-bunyan": "^1.6.3",
     "bunyan": "^1.8.15",
     "bunyan": "^1.8.15",
     "dotenv-flow": "^3.2.0",
     "dotenv-flow": "^3.2.0",

+ 1 - 0
packages/slack/src/index.ts

@@ -12,6 +12,7 @@ export * from './interfaces/request-from-slack';
 export * from './models/errors';
 export * from './models/errors';
 export * from './middlewares/verify-slack-request';
 export * from './middlewares/verify-slack-request';
 export * from './utils/block-creater';
 export * from './utils/block-creater';
+export * from './utils/check-communicable';
 export * from './utils/post-ephemeral-errors';
 export * from './utils/post-ephemeral-errors';
 export * from './utils/slash-command-parser';
 export * from './utils/slash-command-parser';
 export * from './utils/webclient-factory';
 export * from './utils/webclient-factory';

+ 4 - 0
packages/slack/src/interfaces/connection-status.ts

@@ -0,0 +1,4 @@
+export type ConnectionStatus = {
+  error?: Error,
+  workspaceName?: string,
+}

+ 88 - 0
packages/slack/src/utils/check-communicable.ts

@@ -0,0 +1,88 @@
+import axios, { AxiosError } from 'axios';
+
+import { WebClient } from '@slack/web-api';
+
+import { generateWebClient } from './webclient-factory';
+import { ConnectionStatus } from '../interfaces/connection-status';
+
+/**
+ * Check whether the HTTP server responds or not.
+ *
+ * @param serverUri Server URI to connect
+ * @returns AxiosError when error is occured
+ */
+export const connectToHttpServer = async(serverUri: string): Promise<void|AxiosError> => {
+  try {
+    await axios.get(serverUri, { maxRedirects: 0, timeout: 3000 });
+  }
+  catch (err) {
+    return err as AxiosError;
+  }
+};
+
+/**
+ * Check whether the Slack API server responds or not.
+ *
+ * @returns AxiosError when error is occured
+ */
+export const connectToSlackApiServer = async(): Promise<void|AxiosError> => {
+  return connectToHttpServer('https://slack.com/api/');
+};
+
+/**
+ * Test Slack API
+ * @param client
+ */
+const testSlackApiServer = async(client: WebClient): Promise<void> => {
+  const result = await client.api.test();
+
+  if (!result.ok) {
+    throw new Error(result.error);
+  }
+};
+
+/**
+ * Retrieve Slack workspace name
+ * @param client
+ */
+const retrieveWorkspaceName = async(client: WebClient): Promise<string> => {
+  const result = await client.team.info();
+
+  if (!result.ok) {
+    throw new Error(result.error);
+  }
+
+  return (result as any).team?.name;
+};
+
+/**
+ * Get token string to ConnectionStatus map
+ * @param tokens Array of bot OAuth token
+ * @returns
+ */
+export const getConnectionStatuses = async(tokens: string[]): Promise<Map<string, ConnectionStatus>> => {
+  return tokens
+    .reduce<Promise<Map<string, ConnectionStatus>>>(
+      async(acc, token) => {
+        const client = generateWebClient(token);
+
+        const status: ConnectionStatus = {};
+        try {
+          // try to connect
+          await testSlackApiServer(client);
+          // retrieve workspace name
+          status.workspaceName = await retrieveWorkspaceName(client);
+        }
+        catch (err) {
+          status.error = err;
+        }
+
+        (await acc).set(token, status);
+
+        return acc;
+
+      },
+      // define initial accumulator
+      Promise.resolve(new Map<string, ConnectionStatus>()),
+    );
+};

+ 4 - 2
resource/locales/en_US/admin/admin.json

@@ -319,14 +319,16 @@
       "test_connection": "Test Connection",
       "test_connection": "Test Connection",
       "test_connection_by_pressing_button": "Press the button to test the connection",
       "test_connection_by_pressing_button": "Press the button to test the connection",
       "error_check_logs_below": "An error has occurred. Please check the logs below.",
       "error_check_logs_below": "An error has occurred. Please check the logs below.",
-      "send_message_to_slack_work_space": "Send message to Slack work space."
+      "send_message_to_slack_work_space": "Send message to Slack work space.",
+      "add_slack_workspace": "Add a Slack Workspace"
     },
     },
     "custom_bot_without_proxy_integration": "Custom bot without proxy integration",
     "custom_bot_without_proxy_integration": "Custom bot without proxy integration",
     "integration_sentence": {
     "integration_sentence": {
       "integration_is_not_complete": "Integration is not complete.<br>Proceed with the following integration procedure.",
       "integration_is_not_complete": "Integration is not complete.<br>Proceed with the following integration procedure.",
       "integration_successful": "Integration successful"
       "integration_successful": "Integration successful"
     },
     },
-    "custom_bot_with_proxy_integration": "Custom bot with proxy integration"
+    "custom_bot_with_proxy_integration": "Custom bot with proxy integration",
+    "official_bot_integration": "Official bot integration"
   },
   },
   "user_management": {
   "user_management": {
     "invite_users": "Temporarily issue a new user",
     "invite_users": "Temporarily issue a new user",

+ 5 - 3
resource/locales/ja_JP/admin/admin.json

@@ -289,7 +289,7 @@
     "delete": "削除",
     "delete": "削除",
     "cooperation_procedure": "連携手順",
     "cooperation_procedure": "連携手順",
     "custom_bot_without_proxy_settings": "Custom Bot (Without-Proxy) 設定",
     "custom_bot_without_proxy_settings": "Custom Bot (Without-Proxy) 設定",
-    "reset":"リセット",
+    "reset": "リセット",
     "delete_slackbot_settings": "Slack Bot 設定をリセットする",
     "delete_slackbot_settings": "Slack Bot 設定をリセットする",
     "slackbot_settings_notice": "リセットします",
     "slackbot_settings_notice": "リセットします",
     "accordion": {
     "accordion": {
@@ -316,14 +316,16 @@
       "test_connection": "連携状況のテストをする",
       "test_connection": "連携状況のテストをする",
       "test_connection_by_pressing_button": "以下のテストボタンを押して、Slack連携が完了しているかの確認をしましょう",
       "test_connection_by_pressing_button": "以下のテストボタンを押して、Slack連携が完了しているかの確認をしましょう",
       "error_check_logs_below": "エラーが発生しました。下記のログを確認してください。",
       "error_check_logs_below": "エラーが発生しました。下記のログを確認してください。",
-      "send_message_to_slack_work_space": "Slack ワークスペースに送信しました"
+      "send_message_to_slack_work_space": "Slack ワークスペースに送信しました",
+      "add_slack_workspace": "Slackワークスペースを追加"
     },
     },
     "custom_bot_without_proxy_integration": "Custom bot without proxy 連携",
     "custom_bot_without_proxy_integration": "Custom bot without proxy 連携",
     "integration_sentence": {
     "integration_sentence": {
       "integration_is_not_complete": "連携は完了していません。<br>下記の連携手順を進めてください。",
       "integration_is_not_complete": "連携は完了していません。<br>下記の連携手順を進めてください。",
       "integration_successful": "連携が完了しました。"
       "integration_successful": "連携が完了しました。"
     },
     },
-    "custom_bot_with_proxy_integration": "Custom bot with proxy 連携"
+    "custom_bot_with_proxy_integration": "Custom bot with proxy 連携",
+    "official_bot_integration": "Official bot 連携"
   },
   },
   "user_management": {
   "user_management": {
     "invite_users": "新規ユーザーの仮発行",
     "invite_users": "新規ユーザーの仮発行",

+ 4 - 2
resource/locales/zh_CN/admin/admin.json

@@ -326,14 +326,16 @@
       "test_connection": "测试连接",
       "test_connection": "测试连接",
       "test_connection_by_pressing_button": "按下按钮以测试连接",
       "test_connection_by_pressing_button": "按下按钮以测试连接",
       "error_check_logs_below": "发生了错误。请检查以下日志。",
       "error_check_logs_below": "发生了错误。请检查以下日志。",
-      "send_message_to_slack_work_space": "发送到 Slack 工作区。"
+      "send_message_to_slack_work_space": "发送到 Slack 工作区。",
+      "add_slack_workspace": "添加Slack Workspace"
     },
     },
     "custom_bot_without_proxy_integration": "Custom bot without proxy 一体化",
     "custom_bot_without_proxy_integration": "Custom bot without proxy 一体化",
     "integration_sentence": {
     "integration_sentence": {
       "integration_is_not_complete": "一体化未完成。<br>进行以下一体化程序。",
       "integration_is_not_complete": "一体化未完成。<br>进行以下一体化程序。",
       "integration_successful": "一体化成功"
       "integration_successful": "一体化成功"
     },
     },
-    "custom_bot_with_proxy_integration": "Custom bot with proxy 一体化"
+    "custom_bot_with_proxy_integration": "Custom bot with proxy 一体化",
+    "official_bot_integration": "Official bot 一体化"
   },
   },
 	"user_management": {
 	"user_management": {
 		"invite_users": "临时发布新用户",
 		"invite_users": "临时发布新用户",

+ 26 - 12
src/client/js/components/Admin/SlackIntegration/CustomBotWithProxyIntegrationCard.jsx

@@ -11,18 +11,20 @@ const CustomBotWithProxyIntegrationCard = (props) => {
       <div className="card rounded shadow border-0 w-50 admin-bot-card">
       <div className="card rounded shadow border-0 w-50 admin-bot-card">
         <h5 className="card-title font-weight-bold mt-3 ml-4">Slack</h5>
         <h5 className="card-title font-weight-bold mt-3 ml-4">Slack</h5>
         <div className="card-body px-5">
         <div className="card-body px-5">
-          {props.slackWSNameInWithProxy != null && (
-            <div className="card slack-work-space-name-card">
-              <div className="m-2 text-center">
-                <h5 className="font-weight-bold">{props.slackWSNameInWithProxy}</h5>
-                <img width={20} height={20} src="/images/slack-integration/growi-bot-kun-icon.png" />
+          {props.slackWorkSpaces.map((slackWorkSpaceName) => {
+            return (
+              <div key={slackWorkSpaceName.name} className={slackWorkSpaceName.active ? 'card slack-work-space-name-card' : ''}>
+                <div className="m-2 text-center">
+                  <h5 className="font-weight-bold">{slackWorkSpaceName.name}</h5>
+                  <img width={20} height={20} src="/images/slack-integration/growi-bot-kun-icon.png" />
+                </div>
               </div>
               </div>
-            </div>
-          )}
+            );
+          })}
         </div>
         </div>
       </div>
       </div>
 
 
-      <div className="text-center w-25">
+      <div className="text-center w-25 mt-5">
         {props.isSlackScopeSet && (
         {props.isSlackScopeSet && (
           <p className="text-success small">
           <p className="text-success small">
             <i className="fa fa-check mr-1" />
             <i className="fa fa-check mr-1" />
@@ -36,6 +38,7 @@ const CustomBotWithProxyIntegrationCard = (props) => {
             dangerouslySetInnerHTML={{ __html: t('admin:slack_integration.integration_sentence.integration_is_not_complete') }}
             dangerouslySetInnerHTML={{ __html: t('admin:slack_integration.integration_sentence.integration_is_not_complete') }}
           />
           />
         )}
         )}
+
         <div className="pt-2">
         <div className="pt-2">
           <div className="position-relative mt-5">
           <div className="position-relative mt-5">
             <div className="circle position-absolute bg-primary border-light">
             <div className="circle position-absolute bg-primary border-light">
@@ -59,7 +62,18 @@ const CustomBotWithProxyIntegrationCard = (props) => {
           </div>
           </div>
         </div>
         </div>
         <div className="card-body p-4 mb-5 text-center">
         <div className="card-body p-4 mb-5 text-center">
-          <a className="btn btn-primary">{props.siteName}</a>
+          <div className="btn-group-vertical w-50">
+            {props.growiApps.map((growiApp) => {
+              return (
+                <button
+                  type="button"
+                  key={growiApp.name}
+                  className={growiApp.active ? 'btn btn-primary mb-3' : 'btn btn-outline-primary mb-3'}
+                >{growiApp.name}
+                </button>
+              );
+            })}
+          </div>
         </div>
         </div>
       </div>
       </div>
     </div>
     </div>
@@ -67,9 +81,9 @@ const CustomBotWithProxyIntegrationCard = (props) => {
 };
 };
 
 
 CustomBotWithProxyIntegrationCard.propTypes = {
 CustomBotWithProxyIntegrationCard.propTypes = {
-  siteName: PropTypes.string.isRequired,
-  slackWSNameInWithProxy: PropTypes.string,
-  isSlackScopeSet: PropTypes.bool.isRequired,
+  growiApps: PropTypes.array.isRequired,
+  slackWorkSpaces: PropTypes.array,
+  isSlackScopeSet: PropTypes.bool,
 };
 };
 
 
 export default CustomBotWithProxyIntegrationCard;
 export default CustomBotWithProxyIntegrationCard;

+ 14 - 3
src/client/js/components/Admin/SlackIntegration/CustomBotWithProxySettings.jsx

@@ -32,8 +32,19 @@ const CustomBotWithProxySettings = (props) => {
 
 
       {/* TODO delete tmp props */}
       {/* TODO delete tmp props */}
       <CustomBotWithProxyIntegrationCard
       <CustomBotWithProxyIntegrationCard
-        siteName="GROWI"
-        slackWSNameInWithProxy="SlackWorkSpaceName"
+        growiApps={
+          [
+            { name: 'siteName1', active: true },
+            { name: 'siteName2', active: false },
+            { name: 'siteName3', active: false },
+          ]
+        }
+        slackWorkSpaces={
+          [
+            { name: 'wsName1', active: true },
+            { name: 'wsName2', active: false },
+          ]
+        }
         isSlackScopeSet
         isSlackScopeSet
       />
       />
       <h2 className="admin-setting-header">{t('admin:slack_integration.cooperation_procedure')}</h2>
       <h2 className="admin-setting-header">{t('admin:slack_integration.cooperation_procedure')}</h2>
@@ -64,7 +75,7 @@ const CustomBotWithProxySettings = (props) => {
             className="btn btn-outline-primary"
             className="btn btn-outline-primary"
             onClick={addAccordionHandler}
             onClick={addAccordionHandler}
           >
           >
-            + Slackワークスペースを追加
+            {`+ ${t('admin:slack_integration.accordion.add_slack_workspace')}`}
           </button>
           </button>
         </div>
         </div>
       </div>
       </div>

+ 1 - 1
src/client/js/components/Admin/SlackIntegration/DeleteSlackBotSettingsModal.jsx

@@ -46,7 +46,7 @@ const DeleteSlackBotSettingsModal = React.memo((props) => {
         <Button onClick={closeButtonHandler}>{t('Cancel')}</Button>
         <Button onClick={closeButtonHandler}>{t('Cancel')}</Button>
         <Button color="danger" onClick={deleteSlackCredentialsHandler}>
         <Button color="danger" onClick={deleteSlackCredentialsHandler}>
           <i className="icon icon-fire"></i>
           <i className="icon icon-fire"></i>
-          {t('Reset')}
+          {t('admin:slack_integration.reset')}
         </Button>
         </Button>
       </ModalFooter>
       </ModalFooter>
     </Modal>
     </Modal>

+ 20 - 0
src/client/js/components/Admin/SlackIntegration/OfficialBotSettings.jsx

@@ -1,12 +1,32 @@
 import React from 'react';
 import React from 'react';
 import { useTranslation } from 'react-i18next';
 import { useTranslation } from 'react-i18next';
 import OfficialBotSettingsAccordion from './OfficialbotSettingsAccordion';
 import OfficialBotSettingsAccordion from './OfficialbotSettingsAccordion';
+import CustomBotWithProxyIntegrationCard from './CustomBotWithProxyIntegrationCard';
 
 
 const OfficialBotSettings = () => {
 const OfficialBotSettings = () => {
   const { t } = useTranslation();
   const { t } = useTranslation();
 
 
   return (
   return (
     <>
     <>
+      <h2 className="admin-setting-header">{t('admin:slack_integration.official_bot_integration')}</h2>
+      {/* TODO delete tmp props */}
+      <CustomBotWithProxyIntegrationCard
+        growiApps={
+          [
+            { name: 'siteName1', active: true },
+            { name: 'siteName2', active: false },
+            { name: 'siteName3', active: false },
+          ]
+        }
+        slackWorkSpaces={
+          [
+            { name: 'wsName1', active: true },
+            { name: 'wsName2', active: false },
+          ]
+        }
+        isSlackScopeSet
+      />
+
       <h2 className="admin-setting-header">{t('admin:slack_integration.official_bot_settings')}</h2>
       <h2 className="admin-setting-header">{t('admin:slack_integration.official_bot_settings')}</h2>
 
 
       <div className="my-5 mx-3">
       <div className="my-5 mx-3">

+ 36 - 142
src/server/routes/apiv3/slack-integration-settings.js

@@ -1,10 +1,11 @@
 const loggerFactory = require('@alias/logger');
 const loggerFactory = require('@alias/logger');
 
 
+const { getConnectionStatuses } = require('@growi/slack');
+
 const logger = loggerFactory('growi:routes:apiv3:notification-setting');
 const logger = loggerFactory('growi:routes:apiv3:notification-setting');
 const express = require('express');
 const express = require('express');
 const { body } = require('express-validator');
 const { body } = require('express-validator');
 const crypto = require('crypto');
 const crypto = require('crypto');
-const { WebClient, LogLevel } = require('@slack/web-api');
 const ErrorV3 = require('../../models/vo/error-apiv3');
 const ErrorV3 = require('../../models/vo/error-apiv3');
 
 
 const router = express.Router();
 const router = express.Router();
@@ -84,36 +85,44 @@ module.exports = (crowi) => {
    *        tags: [SlackBotSettingParams]
    *        tags: [SlackBotSettingParams]
    *        operationId: getSlackBotSettingParams
    *        operationId: getSlackBotSettingParams
    *        summary: get /slack-integration
    *        summary: get /slack-integration
-   *        description: Get slackBot setting params.
+   *        description: Get current settings and connection statuses.
    *        responses:
    *        responses:
    *          200:
    *          200:
-   *            description: Succeeded to get slackBot setting params.
+   *            description: Succeeded to get info.
    */
    */
   router.get('/', accessTokenParser, loginRequiredStrictly, adminRequired, async(req, res) => {
   router.get('/', accessTokenParser, loginRequiredStrictly, adminRequired, async(req, res) => {
-    const slackBotSettingParams = {
-      accessToken: crowi.configManager.getConfig('crowi', 'slackbot:access-token'),
-      currentBotType: crowi.configManager.getConfig('crowi', 'slackbot:currentBotType'),
-      // TODO impl when creating official bot
-      officialBotSettings: {
-        // TODO impl this after GW-4939
-        // AccessToken: "tempaccessdatahogehoge",
-      },
-      customBotWithoutProxySettings: {
-        // TODO impl this after GW-4939
-        // AccessToken: "tempaccessdatahogehoge",
-        slackSigningSecretEnvVars: crowi.configManager.getConfigFromEnvVars('crowi', 'slackbot:signingSecret'),
-        slackBotTokenEnvVars: crowi.configManager.getConfigFromEnvVars('crowi', 'slackbot:token'),
-        slackSigningSecret: crowi.configManager.getConfig('crowi', 'slackbot:signingSecret'),
-        slackBotToken: crowi.configManager.getConfig('crowi', 'slackbot:token'),
-        isConnectedToSlack: crowi.slackBotService.isConnectedToSlack,
-      },
-      // TODO imple when creating with proxy
-      customBotWithProxySettings: {
-        // TODO impl this after GW-4939
-        // AccessToken: "tempaccessdatahogehoge",
-      },
-    };
-    return res.apiv3({ slackBotSettingParams });
+    const { configManager } = crowi;
+    const currentBotType = configManager.getConfig('crowi', 'slackbot:currentBotType');
+
+    // retrieve settings
+    const settings = {};
+    if (currentBotType === 'customBotWithoutProxy') {
+      settings.slackSigningSecretEnvVars = configManager.getConfigFromEnvVars('crowi', 'slackbot:signingSecret');
+      settings.slackBotTokenEnvVars = configManager.getConfigFromEnvVars('crowi', 'slackbot:token');
+      settings.slackSigningSecret = configManager.getConfig('crowi', 'slackbot:signingSecret');
+      settings.slackBotToken = configManager.getConfig('crowi', 'slackbot:token');
+    }
+    else {
+      // settings.proxyUriEnvVars = ;
+      // settings.proxyUri = ;
+      // settings.tokenPtoG = ;
+      // settings.tokenGtoP = ;
+    }
+
+    // retrieve connection statuses
+    let connectionStatuses;
+    if (currentBotType === 'customBotWithoutProxy') {
+      const token = settings.slackBotToken;
+      // check the token is not null
+      if (token != null) {
+        connectionStatuses = Object.fromEntries(await getConnectionStatuses([]));
+      }
+    }
+    else {
+      // connectionStatuses = getConnectionStatusesFromProxy();
+    }
+
+    return res.apiv3({ currentBotType, settings, connectionStatuses });
   });
   });
 
 
   /**
   /**
@@ -145,9 +154,6 @@ module.exports = (crowi) => {
 
 
       try {
       try {
         await updateSlackBotSettings(requestParams);
         await updateSlackBotSettings(requestParams);
-
-        // initialize slack service
-        await crowi.slackBotService.initialize();
         crowi.slackBotService.publishUpdatedMessage();
         crowi.slackBotService.publishUpdatedMessage();
 
 
         const slackIntegrationSettingsParams = {
         const slackIntegrationSettingsParams = {
@@ -191,9 +197,6 @@ module.exports = (crowi) => {
       };
       };
       try {
       try {
         await updateSlackBotSettings(requestParams);
         await updateSlackBotSettings(requestParams);
-
-        // initialize slack service
-        await crowi.slackBotService.initialize();
         crowi.slackBotService.publishUpdatedMessage();
         crowi.slackBotService.publishUpdatedMessage();
 
 
         // TODO Impl to delete AccessToken both of Proxy and GROWI when botType changes.
         // TODO Impl to delete AccessToken both of Proxy and GROWI when botType changes.
@@ -247,114 +250,5 @@ module.exports = (crowi) => {
 
 
   });
   });
 
 
-  /**
-   * @swagger
-   *
-   *    /slack-integration/access-token:
-   *      put:
-   *        tags: [SlackIntegration]
-   *        operationId: getCustomBotSetting
-   *        summary: /slack-integration
-   *        description: Generate accessToken
-   *        responses:
-   *          200:
-   *            description: Succeeded to update access token for slack
-   */
-  router.put('/access-token', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
-
-    try {
-      const accessToken = generateAccessToken(req.user);
-      await updateSlackBotSettings({ 'slackbot:access-token': accessToken });
-
-      // initialize slack service
-      await crowi.slackBotService.initialize();
-      crowi.slackBotService.publishUpdatedMessage();
-
-      return res.apiv3({ accessToken });
-    }
-    catch (error) {
-      const msg = 'Error occured in updating access token for access token';
-      logger.error('Error', error);
-      return res.apiv3Err(new ErrorV3(msg, 'update-accessToken-failed'), 500);
-    }
-  });
-
-  /**
-   * @swagger
-   *
-   *    /slack-integration/test-notification-to-slack-work-space:
-   *      post:
-   *        tags: [SlackTestToWorkSpace]
-   *        operationId: postSlackMessageToSlackWorkSpace
-   *        summary: test to send message to slack work space
-   *        description: post message to slack work space
-   *        responses:
-   *          200:
-   *            description: Succeeded to send a message to slack work space
-   */
-  router.post('/notification-test-to-slack-work-space',
-    loginRequiredStrictly, adminRequired, csrf, validator.NotificationTestToSlackWorkSpace, apiV3FormValidator, async(req, res) => {
-      const isConnectedToSlack = crowi.slackBotService.isConnectedToSlack;
-      const { channel } = req.body;
-
-      if (isConnectedToSlack === false) {
-        const msg = 'Bot User OAuth Token is not setup.';
-        logger.error('Error', msg);
-        return res.apiv3Err(new ErrorV3(msg, 'not-setup-slack-bot-token', 400));
-      }
-
-      const slackBotToken = crowi.configManager.getConfig('crowi', 'slackbot:token');
-      this.client = new WebClient(slackBotToken, { logLevel: LogLevel.DEBUG });
-      logger.debug('SlackBot: setup is done');
-
-      try {
-        await this.client.chat.postMessage({
-          channel: `#${channel}`,
-          text: 'Your test was successful!',
-        });
-        logger.info(`SlackTest: send success massage to slack work space at #${channel}.`);
-        logger.info(`If you do not receive a message, you may not have invited the bot to the #${channel} channel.`);
-        // eslint-disable-next-line max-len
-        const message = `Successfully send message to Slack work space. See #general channel. If you do not receive a message, you may not have invited the bot to the #${channel} channel.`;
-        return res.apiv3({ message });
-      }
-      catch (error) {
-        const msg = `Error: ${error.data.error}. Needed:${error.data.needed}`;
-        logger.error('Error', error);
-        return res.apiv3Err(new ErrorV3(msg, 'notification-test-slack-work-space-failed'), 500);
-      }
-    });
-
-  /**
-   * @swagger
-   *
-   *    /slack-integration/access-token:
-   *      delete:
-   *        tags: [SlackIntegration]
-   *        operationId: deleteAccessTokenForSlackBot
-   *        summary: /slack-integration
-   *        description: Delete accessToken
-   *        responses:
-   *          200:
-   *            description: Succeeded to delete accessToken
-   */
-  router.delete('/access-token', loginRequiredStrictly, adminRequired, csrf, async(req, res) => {
-
-    try {
-      await updateSlackBotSettings({ 'slackbot:access-token': null });
-
-      // initialize slack service
-      await crowi.slackBotService.initialize();
-      crowi.slackBotService.publishUpdatedMessage();
-
-      return res.apiv3({});
-    }
-    catch (error) {
-      const msg = 'Error occured in discard of slackbotAccessToken';
-      logger.error('Error', error);
-      return res.apiv3Err(new ErrorV3(msg, 'discard-slackbotAccessToken-failed'), 500);
-    }
-  });
-
   return router;
   return router;
 };
 };

+ 0 - 6
src/server/service/config-loader.js

@@ -410,12 +410,6 @@ const ENV_VAR_NAME_TO_CONFIG_INFO = {
     type:    TYPES.STRING,
     type:    TYPES.STRING,
     default: null,
     default: null,
   },
   },
-  SLACK_BOT_ACCESS_TOKEN: {
-    ns:      'crowi',
-    key:     'slackbot:access-token',
-    type:    TYPES.STRING,
-    default: null,
-  },
   SLACK_BOT_TYPE: {
   SLACK_BOT_TYPE: {
     ns:      'crowi',
     ns:      'crowi',
     key:     'slackbot:currentBotType', // 'officialBot' || 'customBotWithoutProxy' || 'customBotWithProxy'
     key:     'slackbot:currentBotType', // 'officialBot' || 'customBotWithoutProxy' || 'customBotWithProxy'

+ 21 - 26
src/server/service/slackbot.js

@@ -1,10 +1,10 @@
 const logger = require('@alias/logger')('growi:service:SlackBotService');
 const logger = require('@alias/logger')('growi:service:SlackBotService');
 const mongoose = require('mongoose');
 const mongoose = require('mongoose');
 
 
-const PAGINGLIMIT = 10;
-
 const { generateWebClient } = require('@growi/slack');
 const { generateWebClient } = require('@growi/slack');
 
 
+const PAGINGLIMIT = 10;
+
 const S2sMessage = require('../models/vo/s2s-message');
 const S2sMessage = require('../models/vo/s2s-message');
 const S2sMessageHandlable = require('./s2s-messaging/handlable');
 const S2sMessageHandlable = require('./s2s-messaging/handlable');
 
 
@@ -16,40 +16,36 @@ class SlackBotService extends S2sMessageHandlable {
     this.crowi = crowi;
     this.crowi = crowi;
     this.s2sMessagingService = crowi.s2sMessagingService;
     this.s2sMessagingService = crowi.s2sMessagingService;
 
 
-    this.client = null;
-    this.searchService = null;
-
-    this.isConnectedToSlack = false;
-
     this.lastLoadedAt = null;
     this.lastLoadedAt = null;
 
 
     this.initialize();
     this.initialize();
   }
   }
 
 
-  async initialize() {
-    this.isConnectedToSlack = false;
+  initialize() {
+    this.lastLoadedAt = new Date();
+  }
+
+  get client() {
     const currentBotType = this.crowi.configManager.getConfig('crowi', 'slackbot:currentBotType');
     const currentBotType = this.crowi.configManager.getConfig('crowi', 'slackbot:currentBotType');
 
 
-    if (currentBotType != null) {
-      let serverUri;
-      let token;
+    if (currentBotType == null) {
+      throw new Error('The config \'SLACK_BOT_TYPE\'(ns: \'crowi\', key: \'slackbot:currentBotType\') must be set.');
+    }
 
 
-      // connect to proxy
-      if (currentBotType !== 'customBotWithoutProxy') {
-        // TODO: https://youtrack.weseek.co.jp/issue/GW-5896
-        serverUri = 'http://localhost:8080/slack-api-proxy/';
-      }
-      // connect directly
-      else {
-        token = this.crowi.configManager.getConfig('crowi', 'slackbot:token');
-      }
+    let serverUri;
+    let token;
 
 
-      this.client = generateWebClient(token, serverUri);
-      logger.debug('SlackBot: setup is done');
-      await this.sendAuthTest();
+    // connect to proxy
+    if (currentBotType !== 'customBotWithoutProxy') {
+      // TODO: https://youtrack.weseek.co.jp/issue/GW-5896
+      serverUri = 'http://localhost:8080/slack-api-proxy/';
+    }
+    // connect directly
+    else {
+      token = this.crowi.configManager.getConfig('crowi', 'slackbot:token');
     }
     }
 
 
-    this.lastLoadedAt = new Date();
+    return generateWebClient(token, serverUri);
   }
   }
 
 
   /**
   /**
@@ -93,7 +89,6 @@ class SlackBotService extends S2sMessageHandlable {
 
 
   async sendAuthTest() {
   async sendAuthTest() {
     await this.client.api.test();
     await this.client.api.test();
-    this.isConnectedToSlack = true;
   }
   }
 
 
   notCommand(body) {
   notCommand(body) {