فهرست منبع

Merge branch 'feat/growi-bot' into imprv/gw5547-new

# Conflicts:
#	packages/slackbot-proxy/src/controllers/slack.ts
#	packages/slackbot-proxy/src/services/InstallerService.ts
kaori 5 سال پیش
والد
کامیت
861b981abf

+ 1 - 0
packages/slackbot-proxy/package.json

@@ -26,6 +26,7 @@
     "@tsed/platform-express": "^6.43.0",
     "@tsed/swagger": "^6.43.0",
     "@tsed/typeorm": "^6.43.0",
+    "axios": "^0.21.1",
     "browser-bunyan": "^1.6.3",
     "bunyan": "^1.8.15",
     "compression": "^1.7.4",

+ 118 - 73
packages/slackbot-proxy/src/controllers/slack.ts

@@ -1,6 +1,9 @@
 import {
   BodyParams, Controller, Get, Inject, Post, Req, Res, UseBefore,
 } from '@tsed/common';
+
+import axios from 'axios';
+
 import { parseSlashCommand } from '@growi/slack';
 import { Installation } from '~/entities/installation';
 
@@ -11,8 +14,9 @@ import { InstallerService } from '~/services/InstallerService';
 import { RegisterService } from '~/services/RegisterService';
 
 import loggerFactory from '~/utils/logger';
-import { AuthorizeMiddleware } from '~/middlewares/authorizer';
+import { AuthorizeCommandMiddleware, AuthorizeInteractionMiddleware } from '~/middlewares/authorizer';
 import { AuthedReq } from '~/interfaces/authorized-req';
+import { Relation } from '~/entities/relation';
 
 const logger = loggerFactory('slackbot-proxy:controllers:slack');
 
@@ -74,7 +78,7 @@ export class SlackCtrl {
   }
 
   @Post('/commands')
-  @UseBefore(AuthorizeMiddleware)
+  @UseBefore(AuthorizeCommandMiddleware)
   async handleCommand(@Req() req: AuthedReq, @Res() res: Res): Promise<void|string> {
     const { body, authorizeResult } = req;
 
@@ -90,86 +94,127 @@ export class SlackCtrl {
       return;
     }
 
-    return;
+    /*
+     * forward to GROWI server
+     */
+    const installationId = authorizeResult.enterpriseId || authorizeResult.teamId;
+    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+    const installation = await this.installationRepository.findByTeamIdOrEnterpriseId(installationId!);
+    const relations = await this.relationRepository.find({ installation: installation?.id });
+
+    await relations.map((relation: Relation) => {
+      // generate API URL
+      const url = new URL('/_api/v3/slack-bot/commands', relation.growiUri);
+      return axios.post(url.toString(), {
+        ...body,
+        tokenPtoG: relation.tokenPtoG,
+        growiCommand,
+      });
+    });
+
+    // return;
   }
 
   @Post('/interactions')
   // TODO: using new middleware (5789 blocking)
   // ~~@UseBefore(AuthorizeMiddleware)~~
+  @UseBefore(AuthorizeInteractionMiddleware)
   async handleInteraction(@Req() req: AuthedReq, @Res() res: Res): Promise<void|string> {
-    const { body, authorizeResult } = req;
-    console.log('authorizeResult', authorizeResult);
-
-    logger.info('receive interaction', body);
-
-    const installation = await this.installationRepository.findByID('1');
-    if (installation == null) {
-      throw new Error('installation is reqiured');
-    }
-
-    const handleViewSubmission = async(inputValues) => {
-
-      const newGrowiUrl = inputValues.growiDomain.contents_input.value;
-      const newGrowiAccessToken = inputValues.growiAccessToken.contents_input.value;
-      const newProxyAccessToken = inputValues.proxyToken.contents_input.value;
-      console.log('newGrowiUrl', newGrowiUrl);
-      console.log('newGrowiAccessToken', newGrowiAccessToken);
-      console.log('newAccessToken', newProxyAccessToken);
-
-      const order = await this.orderRepository;
-
-      const growiUrl = order.metadata.propertiesMap.growiUrl;
-      const growiAccessToken = order.metadata.propertiesMap.growiAccessToken;
-      const proxyAccessToken = order.metadata.propertiesMap.proxyAccessToken;
-
-      console.log('order.metadata.propertiesMap', order.metadata.propertiesMap);
-
-      order.update({ growiUrl }, { growiUrl: newGrowiUrl });
-      order.update({ growiAccessToken }, { growiAccessToken: newGrowiAccessToken });
-      order.update({ proxyAccessToken }, { proxyAccessToken: newProxyAccessToken });
-      res.send();
-
-    };
-
-    if (body.payload != null) {
-      const payload = JSON.parse(body.payload);
-      const { type } = payload;
-      const inputValues = payload.view.state.values;
-
-      try {
-        switch (type) {
-          case 'view_submission':
-            await handleViewSubmission(inputValues);
-            break;
-          default:
-            break;
-        }
-      }
-      catch (error) {
-        throw new Error(error.message);
-      }
-
-    }
-    if (body.text == null) {
-      return 'No text.';
-    }
-
-    // Find the latest order by installationId and GROWIurl
-    let order = await this.orderRepository.findOne({
-      installation: installation.id,
-    }, {
-      order: {
-        createdAt: 'DESC',
-      },
-    });
-
-    if (order == null || order.isExpired()) {
-      order = await this.orderRepository.save({ installation: installation.id });
-    }
-
+    logger.info('receive interaction', req.body);
+    logger.info('receive interaction', req.authorizeResult);
     return;
   }
 
+  // const { body, authorizeResult } = req;
+  // console.log('authorizeResult', authorizeResult);
+  //   logger.info('receive interaction', body);
+
+  //   const installation = await this.installationRepository.findByID('1');
+  //   if (installation == null) {
+  //     throw new Error('installation is reqiured');
+  //   }
+
+  //   const handleViewSubmission = async(inputValues) => {
+
+  //     const newGrowiUrl = inputValues.growiDomain.contents_input.value;
+  //     const newGrowiAccessToken = inputValues.growiAccessToken.contents_input.value;
+  //     const newProxyAccessToken = inputValues.proxyToken.contents_input.value;
+  //     console.log('newGrowiUrl', newGrowiUrl);
+  //     console.log('newGrowiAccessToken', newGrowiAccessToken);
+  //     console.log('newAccessToken', newProxyAccessToken);
+
+  //     const order = await this.orderRepository;
+
+  //     const growiUrl = order.metadata.propertiesMap.growiUrl;
+  //     const growiAccessToken = order.metadata.propertiesMap.growiAccessToken;
+  //     const proxyAccessToken = order.metadata.propertiesMap.proxyAccessToken;
+
+  //     console.log('order.metadata.propertiesMap', order.metadata.propertiesMap);
+
+  //     order.update({ growiUrl }, { growiUrl: newGrowiUrl });
+  //     order.update({ growiAccessToken }, { growiAccessToken: newGrowiAccessToken });
+  //     order.update({ proxyAccessToken }, { proxyAccessToken: newProxyAccessToken });
+  //     res.send();
+
+  //   };
+
+  //   if (body.payload != null) {
+  //     const payload = JSON.parse(body.payload);
+  //     const { type } = payload;
+  //     const inputValues = payload.view.state.values;
+
+  //     try {
+  //       switch (type) {
+  //         case 'view_submission':
+  //           await handleViewSubmission(inputValues);
+  //           break;
+  //         default:
+  //           break;
+  //       }
+  //     }
+  //     catch (error) {
+  //       throw new Error(error.message);
+  //     }
+
+  //   }
+  //   if (body.text == null) {
+  //     return 'No text.';
+  //   }
+
+  //   // Find the latest order by installationId and GROWIurl
+  //   let order = await this.orderRepository.findOne({
+  //     installation: installation.id,
+  //   }, {
+  //     order: {
+  //       createdAt: 'DESC',
+  //     },
+  /*
+     * forward to GROWI server
+     */
+  // const installationId = authorizeResult.enterpriseId || authorizeResult.teamId;
+  // // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+  // const installation = await this.installationRepository.findByTeamIdOrEnterpriseId(installationId!);
+  // const relations = await this.relationRepository.find({ installation: installation?.id });
+
+  // await relations.map((relation: Relation) => {
+  //   // generate API URL
+  //   const url = new URL('/_api/v3/slack-bot/commands', relation.growiUri);
+  //   return axios.post(url.toString(), {
+  //     ...body,
+  //     tokenPtoG: relation.tokenPtoG,
+  //     growiCommand,
+  //   });
+  // });
+  // }
+
+  // @Post('/interactions')
+  // @UseBefore(AuthorizeInteractionMiddleware)
+  // async handleInteraction(@Req() req: AuthedReq, @Res() res: Res): Promise<void|string> {
+  //   logger.info('receive interaction', req.body);
+  //   logger.info('receive interaction', req.authorizeResult);
+  //   return;
+  // }
+
   @Post('/events')
   async handleEvent(@BodyParams() body:{[key:string]:string}, @Res() res: Res): Promise<void|string> {
     // eslint-disable-next-line max-len

+ 45 - 1
packages/slackbot-proxy/src/middlewares/authorizer.ts

@@ -8,7 +8,7 @@ import { InstallationRepository } from '~/repositories/installation';
 import { InstallerService } from '~/services/InstallerService';
 
 @Middleware()
-export class AuthorizeMiddleware implements IMiddleware {
+export class AuthorizeCommandMiddleware implements IMiddleware {
 
   @Inject()
   installerService: InstallerService;
@@ -47,3 +47,47 @@ export class AuthorizeMiddleware implements IMiddleware {
   }
 
 }
+
+
+@Middleware()
+export class AuthorizeInteractionMiddleware implements IMiddleware {
+
+  @Inject()
+  installerService: InstallerService;
+
+  @Inject()
+  installationRepository: InstallationRepository;
+
+  async use(@Req() req: AuthedReq, @Res() res: Res): Promise<void> {
+    const { body } = req;
+
+    const payload = JSON.parse(body.payload);
+
+    // extract id from body
+    const teamId = payload.team?.id;
+    const enterpriseId = body.enterprise?.id;
+
+    if (teamId == null && enterpriseId == null) {
+      res.writeHead(400);
+      return res.end();
+    }
+
+    // create query from body
+    const query: InstallationQuery<boolean> = {
+      teamId,
+      enterpriseId,
+      isEnterpriseInstall: body.is_enterprise_install === 'true',
+    };
+
+    const result = await this.installerService.installer.authorize(query);
+
+    if (result.botToken == null) {
+      res.writeHead(403);
+      return res.end();
+    }
+
+    // set authorized data
+    req.authorizeResult = result;
+  }
+
+}

+ 1 - 1
packages/slackbot-proxy/src/services/InstallerService.ts

@@ -55,8 +55,8 @@ export class InstallerService {
           return;
         },
         fetchInstallation: async(installQuery: InstallationQuery<boolean>) => {
-          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
           const id = installQuery.enterpriseId || installQuery.teamId;
+
           // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
           const installation = await repository.findByTeamIdOrEnterpriseId(id!);
 

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

@@ -306,8 +306,7 @@
     "custom_bot_without_proxy_integration": "Custom bot without proxy integration",
     "integration_sentence": {
       "integration_is_not_complete": "Integration is not complete.<br>Proceed with the following integration procedure.",
-      "proceed_with_the_following_integration_procedure": "Proceed with the following integration procedure.",
-      "integration_sucessed": "integration sucessed"
+      "integration_successful": "Integration successful"
     },
     "custom_bot_with_proxy_integration": "Custom bot with proxy integration"
   },

+ 1 - 2
resource/locales/ja_JP/admin/admin.json

@@ -304,8 +304,7 @@
     "custom_bot_without_proxy_integration": "Custom bot without proxy 連携",
     "integration_sentence": {
       "integration_is_not_complete": "連携は完了していません。<br>下記の連携手順を進めてください。",
-      "proceed_with_the_following_integration_procedure": "下記の連携手順を進めてください。",
-      "integration_sucessed": "連携が完了しました。"
+      "integration_successful": "連携が完了しました。"
     },
     "custom_bot_with_proxy_integration": "Custom bot with proxy 連携"
   },

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

@@ -314,8 +314,7 @@
     "custom_bot_without_proxy_integration": "Custom bot without proxy 一体化",
     "integration_sentence": {
       "integration_is_not_complete": "一体化未完成。<br>进行以下一体化程序。",
-      "proceed_with_the_following_integration_procedure": "进行以下一体化程序。",
-      "integration_sucessed": "一体化成功"
+      "integration_successful": "一体化成功"
     },
     "custom_bot_with_proxy_integration": "Custom bot with proxy 一体化"
   },

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

@@ -13,6 +13,7 @@ const CustomBotWithProxySettings = (props) => {
   return (
     <>
 
+      {/* TODO: GW-5768 */}
       <h2 className="admin-setting-header">{t('admin:slack_integration.custom_bot_with_proxy_integration')}</h2>
 
       <div className="d-flex justify-content-center my-5 bot-integration">

+ 64 - 0
src/client/js/components/Admin/SlackIntegration/CustomBotWithoutProxyIntegrationCard.jsx

@@ -0,0 +1,64 @@
+import React from 'react';
+import { useTranslation } from 'react-i18next';
+import PropTypes from 'prop-types';
+
+const CustomBotWithoutProxyIntegrationCard = (props) => {
+
+  const { t } = useTranslation();
+
+  return (
+    <>
+
+      <div className="d-flex justify-content-center my-5 bot-integration">
+        <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>
+          <div className="card-body p-2 w-50 mx-auto">
+            {props.slackWSNameInWithoutProxy && (
+              <div className="card slack-work-space-name-card">
+                <div className="m-2 text-center">
+                  <h5 className="font-weight-bold">{ props.slackWSNameInWithoutProxy }</h5>
+                  <img width={20} height={20} src="/images/slack-integration/growi-bot-kun-icon.png" />
+                </div>
+              </div>
+            )}
+          </div>
+        </div>
+
+        <div className="text-center w-25">
+          {props.isSetupSlackBot && (
+            <div className="mt-5">
+              <p className="text-success"><small className="fa fa-check"> {t('admin:slack_integration.integration_sentence.integration_successful')}</small></p>
+              <hr className="align-self-center admin-border-success border-success"></hr>
+            </div>
+          )}
+          {!props.isSetupSlackBot && (
+            <div className="mt-4">
+              <small
+                className="text-secondary m-0"
+                // eslint-disable-next-line react/no-danger
+                dangerouslySetInnerHTML={{ __html: t('admin:slack_integration.integration_sentence.integration_is_not_complete') }}
+              />
+              <hr className="align-self-center admin-border-danger border-danger"></hr>
+            </div>
+          )}
+        </div>
+
+        <div className="card rounded-lg shadow border-0 w-50 admin-bot-card">
+          <h5 className="card-title font-weight-bold mt-3 ml-4">GROWI App</h5>
+          <div className="card-body p-4 mb-5 text-center">
+            <div className="btn btn-primary">{ props.siteName }</div>
+          </div>
+        </div>
+      </div>
+
+    </>
+  );
+};
+
+CustomBotWithoutProxyIntegrationCard.propTypes = {
+  siteName: PropTypes.string.isRequired,
+  slackWSNameInWithoutProxy: PropTypes,
+  isSetupSlackBot: PropTypes.bool.isRequired,
+};
+
+export default CustomBotWithoutProxyIntegrationCard;

+ 60 - 59
src/client/js/components/Admin/SlackIntegration/CustomBotWithoutProxySecretTokenSection.jsx

@@ -25,67 +25,68 @@ const CustomBotWithoutProxySecretTokenSection = (props) => {
   };
 
   return (
-    <div className="card-body">
-      <table className="table settings-table">
-        <colgroup>
-          <col className="item-name" />
-          <col className="from-db" />
-          <col className="from-env-vars" />
-        </colgroup>
-        <thead>
-          <tr><th className="border-top-0"></th><th className="border-top-0">Database</th><th className="border-top-0">Environment variables</th></tr>
-        </thead>
-        <tbody>
-          <tr>
-            <th>Signing Secret</th>
-            <td>
-              <input
-                className="form-control"
-                type="text"
-                value={props.slackSigningSecret || ''}
-                onChange={e => onChangeSigningSecretHandler(e.target.value)}
-              />
-            </td>
-            <td>
-              <input
-                className="form-control"
-                type="text"
-                value={props.slackSigningSecretEnv || ''}
-                readOnly
-              />
-              <p className="form-text text-muted">
-                {/* eslint-disable-next-line react/no-danger */}
-                <small dangerouslySetInnerHTML={{ __html: t('admin:slack_integration.use_env_var_if_empty', { variable: 'SLACK_SIGNING_SECRET' }) }} />
-              </p>
-            </td>
-          </tr>
-          <tr>
-            <th>Bot User OAuth Token</th>
-            <td>
-              <input
-                className="form-control"
-                type="text"
-                value={props.slackBotToken || ''}
-                onChange={e => onChangeBotTokenHandler(e.target.value)}
-              />
-            </td>
-            <td>
-              <input
-                className="form-control"
-                type="text"
-                value={props.slackBotTokenEnv || ''}
-                readOnly
-              />
-              <p className="form-text text-muted">
-                {/* eslint-disable-next-line react/no-danger */}
-                <small dangerouslySetInnerHTML={{ __html: t('admin:slack_integration.use_env_var_if_empty', { variable: 'SLACK_BOT_TOKEN' }) }} />
-              </p>
-            </td>
-          </tr>
-        </tbody>
-      </table>
+    <div className="w-75 mx-auto">
+
+      <h3>Signing Secret</h3>
+      <div className="row">
+
+        <div className="col-sm">
+          <p>Database</p>
+          <input
+            className="form-control"
+            type="text"
+            value={props.slackSigningSecret || ''}
+            onChange={e => onChangeSigningSecretHandler(e.target.value)}
+          />
+        </div>
+
+        <div className="col-sm">
+          <p>Environment variables</p>
+          <input
+            className="form-control"
+            type="text"
+            value={props.slackSigningSecretEnv || ''}
+            readOnly
+          />
+          <p className="form-text text-muted">
+            {/* eslint-disable-next-line react/no-danger */}
+            <small dangerouslySetInnerHTML={{ __html: t('admin:slack_integration.use_env_var_if_empty', { variable: 'SLACK_SIGNING_SECRET' }) }} />
+          </p>
+        </div>
+
+      </div>
+
+      <h3>Bot User OAuth Token</h3>
+      <div className="row">
+
+        <div className="col-sm">
+          <p>Database</p>
+          <input
+            className="form-control"
+            type="text"
+            value={props.slackBotToken || ''}
+            onChange={e => onChangeBotTokenHandler(e.target.value)}
+          />
+        </div>
+
+        <div className="col-sm">
+          <p>Environment variables</p>
+          <input
+            className="form-control"
+            type="text"
+            value={props.slackBotTokenEnv || ''}
+            readOnly
+          />
+          <p className="form-text text-muted">
+            {/* eslint-disable-next-line react/no-danger */}
+            <small dangerouslySetInnerHTML={{ __html: t('admin:slack_integration.use_env_var_if_empty', { variable: 'SLACK_BOT_TOKEN' }) }} />
+          </p>
+        </div>
+
+      </div>
 
       <AdminUpdateButtonRow onClick={updateSecretTokenHandler} disabled={false} />
+
     </div>
   );
 };

+ 9 - 63
src/client/js/components/Admin/SlackIntegration/CustomBotWithoutProxySettings.jsx

@@ -1,86 +1,32 @@
-import React, { useState, useEffect, useCallback } from 'react';
+import React, { useState, useEffect } from 'react';
 import { useTranslation } from 'react-i18next';
 import PropTypes from 'prop-types';
 import AppContainer from '../../../services/AppContainer';
 import AdminAppContainer from '../../../services/AdminAppContainer';
 import { withUnstatedContainers } from '../../UnstatedUtils';
-import { toastError } from '../../../util/apiNotification';
 import CustomBotWithoutProxySettingsAccordion, { botInstallationStep } from './CustomBotWithoutProxySettingsAccordion';
+import CustomBotWithoutProxyIntegrationCard from './CustomBotWithoutProxyIntegrationCard';
 
 const CustomBotWithoutProxySettings = (props) => {
   const { appContainer } = props;
   const { t } = useTranslation();
 
-  const [slackWSNameInWithoutProxy, setSlackWSNameInWithoutProxy] = useState(null);
-
   const [siteName, setSiteName] = useState('');
 
-  const fetchSlackWorkSpaceName = useCallback(async() => {
-    try {
-      const res = await appContainer.apiv3.get('/slack-integration/custom-bot-without-proxy/slack-workspace-name');
-      setSlackWSNameInWithoutProxy(res.data.slackWorkSpaceName);
-    }
-    catch (err) {
-      toastError(err);
-    }
-  }, [appContainer.apiv3]);
-
   useEffect(() => {
-
     const siteName = appContainer.config.crowi.title;
     setSiteName(siteName);
-
-    if (props.isSetupSlackBot) {
-      fetchSlackWorkSpaceName();
-    }
-  }, [appContainer, fetchSlackWorkSpaceName, props.isSetupSlackBot]);
+  }, [appContainer]);
 
   return (
     <>
-
       <h2 className="admin-setting-header">{t('admin:slack_integration.custom_bot_without_proxy_integration')}</h2>
 
-      <div className="d-flex justify-content-center my-5 bot-integration">
-        <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>
-          <div className="card-body p-2 w-50 mx-auto">
-            {slackWSNameInWithoutProxy && (
-              <div className="card p-20 slack-work-space-name-card">
-                <div className="m-2 text-center">
-                  <h5 className="font-weight-bold">{ slackWSNameInWithoutProxy }</h5>
-                  <img width={20} height={20} src="/images/slack-integration/growi-bot-kun-icon.png" />
-                </div>
-              </div>
-            )}
-          </div>
-        </div>
-
-        <div className="text-center w-25">
-          {props.isSetupSlackBot && (
-            <div className="mt-5">
-              <p className="text-success"><small className="fa fa-check"> {t('admin:slack_integration.integration_sentence.integration_sucessed')}</small></p>
-              <hr className="align-self-center admin-border-success border-success"></hr>
-            </div>
-          )}
-          {!props.isSetupSlackBot && (
-            <div className="mt-4">
-              <small
-                className="text-secondary m-0"
-                // eslint-disable-next-line react/no-danger
-                dangerouslySetInnerHTML={{ __html: t('admin:slack_integration.integration_sentence.integration_is_not_complete') }}
-              />
-              <hr className="align-self-center admin-border-danger border-danger"></hr>
-            </div>
-          )}
-        </div>
-
-        <div className="card rounded-lg shadow border-0 w-50 admin-bot-card">
-          <h5 className="card-title font-weight-bold mt-3 ml-4">GROWI App</h5>
-          <div className="card-body p-4 mb-5 text-center">
-            <div className="btn btn-primary">{ siteName }</div>
-          </div>
-        </div>
-      </div>
+      <CustomBotWithoutProxyIntegrationCard
+        siteName={siteName}
+        slackWSNameInWithoutProxy={props.slackWSNameInWithoutProxy}
+        isSetupSlackBot={props.isSetupSlackBot}
+      />
 
       <h2 className="admin-setting-header">{t('admin:slack_integration.custom_bot_without_proxy_settings')}</h2>
 
@@ -90,7 +36,6 @@ const CustomBotWithoutProxySettings = (props) => {
           activeStep={botInstallationStep.CREATE_BOT}
         />
       </div>
-
     </>
   );
 };
@@ -107,6 +52,7 @@ CustomBotWithoutProxySettings.propTypes = {
   isRgisterSlackCredentials: PropTypes.bool,
   isConnectedToSlack: PropTypes.bool,
   isSetupSlackBot: PropTypes.bool,
+  slackWSNameInWithoutProxy: PropTypes.string,
 };
 
 export default CustomBotWithoutProxySettingsWrapper;

+ 11 - 10
src/client/js/components/Admin/SlackIntegration/CustomBotWithoutProxySettingsAccordion.jsx

@@ -16,10 +16,10 @@ export const botInstallationStep = {
 };
 
 const CustomBotWithoutProxySettingsAccordion = ({
-  appContainer, activeStep,
+  appContainer, activeStep, fetchSlackIntegrationData,
   slackSigningSecret, slackSigningSecretEnv, slackBotToken, slackBotTokenEnv,
-  isRegisterSlackCredentials, isSendTestMessage, isConnectedToSlack,
-  onSetSlackSigningSecret, onSetSlackBotToken, onSetIsSendTestMessage, onSetIsRegisterSlackCredentials,
+  isRegisterSlackCredentials, isSendTestMessage,
+  onSetSlackSigningSecret, onSetSlackBotToken, onSetIsSendTestMessage,
 }) => {
   const { t } = useTranslation();
   // TODO: GW-5644 Store default open accordion
@@ -31,6 +31,7 @@ const CustomBotWithoutProxySettingsAccordion = ({
   const [testChannel, setTestChannel] = useState('');
   const currentBotType = 'customBotWithoutProxy';
 
+
   const updateSecretTokenHandler = async() => {
     try {
       await appContainer.apiv3.put('/slack-integration/custom-bot-without-proxy', {
@@ -39,17 +40,13 @@ const CustomBotWithoutProxySettingsAccordion = ({
         currentBotType,
       });
 
-      if (isConnectedToSlack) {
-        onSetIsRegisterSlackCredentials(true);
-      }
-      else {
-        onSetIsRegisterSlackCredentials(false);
-        onSetIsSendTestMessage(false);
+      if (fetchSlackIntegrationData == null) {
+        return null;
       }
+      fetchSlackIntegrationData();
       toastSuccess(t('toaster.update_successed', { target: t('admin:slack_integration.custom_bot_without_proxy_settings') }));
     }
     catch (err) {
-      onSetIsRegisterSlackCredentials(false);
       toastError(err);
     }
   };
@@ -215,12 +212,16 @@ CustomBotWithoutProxySettingsAccordion.propTypes = {
   isRegisterSlackCredentials: PropTypes.bool,
   isSendTestMessage: PropTypes.bool,
   isConnectedToSlack: PropTypes.bool,
+  fetchSlackIntegrationData: PropTypes.func,
   onSetSlackSigningSecret: PropTypes.func,
   onSetSlackBotToken: PropTypes.func,
   onSetIsSendTestMessage: PropTypes.func,
   onSetIsRegisterSlackCredentials: PropTypes.func,
+  setSlackWSNameInWithoutProxy: PropTypes.func,
+
   adminAppContainer: PropTypes.instanceOf(AdminAppContainer).isRequired,
   activeStep: PropTypes.oneOf(Object.values(botInstallationStep)).isRequired,
+  isSetupSlackBot: PropTypes.bool,
 };
 
 export default CustomBotWithoutProxySettingsAccordionWrapper;

+ 31 - 6
src/client/js/components/Admin/SlackIntegration/SlackIntegration.jsx

@@ -26,9 +26,22 @@ const SlackIntegration = (props) => {
   const [isRegisterSlackCredentials, setIsRegisterSlackCredentials] = useState(false);
   const [isSendTestMessage, setIsSendTestMessage] = useState(false);
   const [isSetupSlackBot, setIsSetupSlackBot] = useState(false);
+  const [slackWSNameInWithoutProxy, setSlackWSNameInWithoutProxy] = useState(null);
 
+  const fetchSlackWorkSpaceNameInWithoutProxy = useCallback(async() => {
+    if (!isConnectedToSlack) {
+      return setSlackWSNameInWithoutProxy(null);
+    }
+    try {
+      const res = await appContainer.apiv3.get('/slack-integration/custom-bot-without-proxy/slack-workspace-name');
+      setSlackWSNameInWithoutProxy(res.data.slackWorkSpaceName);
+    }
+    catch (err) {
+      toastError(err);
+    }
+  }, [appContainer.apiv3, isConnectedToSlack]);
 
-  const fetchData = useCallback(async() => {
+  const fetchSlackIntegrationData = useCallback(async() => {
     try {
       const response = await appContainer.apiv3.get('slack-integration/');
       const { currentBotType, customBotWithoutProxySettings } = response.data.slackBotSettingParams;
@@ -45,18 +58,26 @@ const SlackIntegration = (props) => {
       setIsSetupSlackBot(isSetupSlackBot);
       setIsConnectedToSlack(isConnectedToSlack);
 
+      fetchSlackWorkSpaceNameInWithoutProxy();
+
       if (isConnectedToSlack) {
         setIsRegisterSlackCredentials(true);
       }
+      else {
+        setIsRegisterSlackCredentials(false);
+        setIsSendTestMessage(false);
+      }
+
     }
     catch (err) {
       toastError(err);
     }
-  }, [appContainer.apiv3]);
+  }, [appContainer.apiv3, fetchSlackWorkSpaceNameInWithoutProxy]);
+
 
   useEffect(() => {
-    fetchData();
-  }, [fetchData]);
+    fetchSlackIntegrationData();
+  }, [fetchSlackIntegrationData]);
 
   const handleBotTypeSelect = (clickedBotType) => {
     if (clickedBotType === currentBotType) {
@@ -84,9 +105,12 @@ const SlackIntegration = (props) => {
       setSelectedBotType(null);
       toastSuccess(t('admin:slack_integration.bot_reset_successful'));
       setIsRegisterSlackCredentials(false);
+      setIsConnectedToSlack(false);
       setSlackSigningSecret(null);
       setSlackBotToken(null);
+      setIsConnectedToSlack(false);
       setIsSendTestMessage(false);
+      setSlackWSNameInWithoutProxy(null);
     }
     catch (err) {
       toastError(err);
@@ -105,15 +129,16 @@ const SlackIntegration = (props) => {
           isSendTestMessage={isSendTestMessage}
           isRegisterSlackCredentials={isRegisterSlackCredentials}
           isConnectedToSlack={isConnectedToSlack}
+          isSetupSlackBot={isSetupSlackBot}
           slackBotTokenEnv={slackBotTokenEnv}
           slackBotToken={slackBotToken}
           slackSigningSecretEnv={slackSigningSecretEnv}
           slackSigningSecret={slackSigningSecret}
-          isSetupSlackBot={isSetupSlackBot}
+          slackWSNameInWithoutProxy={slackWSNameInWithoutProxy}
           onSetSlackSigningSecret={setSlackSigningSecret}
           onSetSlackBotToken={setSlackBotToken}
           onSetIsSendTestMessage={setIsSendTestMessage}
-          onSetIsRegisterSlackCredentials={setIsRegisterSlackCredentials}
+          fetchSlackIntegrationData={fetchSlackIntegrationData}
         />
       );
       break;