Forráskód Böngészése

Merge branch 'feat/growi-bot' into feat/GW-5749-integration-diagram-component

# Conflicts:
#	src/client/js/components/Admin/SlackIntegration/CustomBotWithoutProxySettings.jsx
Shun Miyazawa 5 éve
szülő
commit
f03a1b399e

+ 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",

+ 50 - 33
packages/slackbot-proxy/src/controllers/slack.ts

@@ -1,6 +1,9 @@
 import {
-  BodyParams, Controller, Get, Inject, Post, Req, Res,
+  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,6 +14,9 @@ import { InstallerService } from '~/services/InstallerService';
 import { RegisterService } from '~/services/RegisterService';
 
 import loggerFactory from '~/utils/logger';
+import { AuthorizeCommandMiddleware, AuthorizeInteractionMiddleware } from '~/middlewares/authorizer';
+import { AuthedReq } from '~/interfaces/authorized-req';
+import { Relation } from '~/entities/relation';
 
 const logger = loggerFactory('slackbot-proxy:controllers:slack');
 
@@ -32,10 +38,6 @@ export class SlackCtrl {
   @Inject()
   registerService: RegisterService;
 
-  growiCommandsMappings = {
-    register: async(body:{[key:string]:string}):Promise<void> => this.registerService.execSlashCommand(body),
-  };
-
   @Get('/testsave')
   testsave(): void {
     const installation = new Installation();
@@ -75,50 +77,65 @@ export class SlackCtrl {
       + '</a>';
   }
 
-  @Post('/events')
-  async handleEvent(@BodyParams() body:{[key:string]:string}, @Res() res: Res): Promise<string> {
-    // eslint-disable-next-line max-len
-    // see: https://api.slack.com/apis/connections/events-api#the-events-api__subscribing-to-event-types__events-api-request-urls__request-url-configuration--verification
-    if (body.type === 'url_verification') {
-      return body.challenge;
-    }
+  @Post('/commands')
+  @UseBefore(AuthorizeCommandMiddleware)
+  async handleCommand(@Req() req: AuthedReq, @Res() res: Res): Promise<void|string> {
+    const { body, authorizeResult } = req;
 
     if (body.text == null) {
       return 'No text.';
     }
 
-    const parsedBody = parseSlashCommand(body);
-    const executeGrowiCommand = this.growiCommandsMappings[parsedBody.growiCommandType];
-
-    if (executeGrowiCommand == null) {
-      return 'No executeGrowiCommand';
-    }
-
     // Send response immediately to avoid opelation_timeout error
     // See https://api.slack.com/apis/connections/events-api#the-events-api__responding-to-events
     res.send();
 
-    await executeGrowiCommand(body);
+    const growiCommand = parseSlashCommand(body);
 
-    const installation = await this.installationRepository.findByID('1');
-    if (installation == null) {
-      throw new Error('installation is reqiured');
+    // register
+    if (growiCommand.growiCommandType === 'register') {
+      await this.registerService.process(growiCommand, authorizeResult, body as {[key:string]:string});
+      return;
     }
 
-    // Find the latest order by installationId
-    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,
+      });
     });
+  }
 
-    if (order == null || order.isExpired()) {
-      order = await this.orderRepository.save({ installation: installation.id });
+  @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
+    // see: https://api.slack.com/apis/connections/events-api#the-events-api__subscribing-to-event-types__events-api-request-urls__request-url-configuration--verification
+    if (body.type === 'url_verification') {
+      return body.challenge;
     }
 
-    return 'This action will be handled by bolt service.';
+    logger.info('receive event', body);
+
+    return;
   }
 
   @Get('/oauth_redirect')

+ 6 - 0
packages/slackbot-proxy/src/interfaces/authorized-req.ts

@@ -0,0 +1,6 @@
+import { AuthorizeResult } from '@slack/oauth';
+import { Req } from '@tsed/common';
+
+export type AuthedReq = Req & {
+  authorizeResult: AuthorizeResult,
+};

+ 6 - 0
packages/slackbot-proxy/src/interfaces/growi-command-processor.ts

@@ -0,0 +1,6 @@
+import { AuthorizeResult } from '@slack/oauth';
+import { GrowiCommand } from '@growi/slack';
+
+export interface GrowiCommandProcessor {
+  process(growiCommand: GrowiCommand, authorizeResult: AuthorizeResult, body: {[key:string]:string}): Promise<void>
+}

+ 0 - 3
packages/slackbot-proxy/src/interfaces/growi-commands-mappings.ts

@@ -1,3 +0,0 @@
-export interface GrowiCommandsMappings{
-  execSlashCommand(body:{[key:string]:string}):Promise<void>
-}

+ 93 - 0
packages/slackbot-proxy/src/middlewares/authorizer.ts

@@ -0,0 +1,93 @@
+import { InstallationQuery } from '@slack/oauth';
+import {
+  IMiddleware, Inject, Middleware, Req, Res,
+} from '@tsed/common';
+
+import { AuthedReq } from '~/interfaces/authorized-req';
+import { InstallationRepository } from '~/repositories/installation';
+import { InstallerService } from '~/services/InstallerService';
+
+@Middleware()
+export class AuthorizeCommandMiddleware implements IMiddleware {
+
+  @Inject()
+  installerService: InstallerService;
+
+  @Inject()
+  installationRepository: InstallationRepository;
+
+  async use(@Req() req: AuthedReq, @Res() res: Res): Promise<void> {
+    const { body } = req;
+
+    // extract id from body
+    const teamId = body.team_id;
+    const enterpriseId = body.enterprize_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;
+  }
+
+}
+
+
+@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;
+  }
+
+}

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

@@ -55,16 +55,16 @@ export class InstallerService {
           return;
         },
         fetchInstallation: async(installQuery: InstallationQuery<boolean>) => {
-          const installation: SlackInstallation<'v1' | 'v2', boolean> = {
-            team: undefined,
-            enterprise: undefined,
-            user: {
-              id: '',
-              token: undefined,
-              scopes: undefined,
-            },
-          };
-          return installation;
+          const id = installQuery.enterpriseId || installQuery.teamId;
+
+          // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+          const installation = await repository.findByTeamIdOrEnterpriseId(id!);
+
+          if (installation == null) {
+            throw new Error('Failed fetching installation');
+          }
+
+          return installation.data;
         },
       },
     });

+ 0 - 16
packages/slackbot-proxy/src/services/RecieveService.ts

@@ -1,16 +0,0 @@
-import { Service } from '@tsed/di';
-import { parseSlashCommand } from '@growi/slack';
-
-@Service()
-export class ReceiveService {
-
-  receiveContentsFromSlack(body:{[key:string]:string}) : string {
-    const parseBody = parseSlashCommand(body);
-    if (parseBody.growiCommandType === 'register') {
-      console.log('register action occured');
-      return 'register action occurd';
-    }
-    return 'return receiveContentsFromSlack';
-  }
-
-}

+ 10 - 5
packages/slackbot-proxy/src/services/RegisterService.ts

@@ -1,14 +1,19 @@
 import { Service } from '@tsed/di';
 import { WebClient, LogLevel } from '@slack/web-api';
-import { generateInputSectionBlock } from '@growi/slack';
-import { GrowiCommandsMappings } from '../interfaces/growi-commands-mappings';
+import { generateInputSectionBlock, GrowiCommand } from '@growi/slack';
+import { AuthorizeResult } from '@slack/oauth';
+
+import { GrowiCommandProcessor } from '~/interfaces/growi-command-processor';
 
 @Service()
-export class RegisterService implements GrowiCommandsMappings {
+export class RegisterService implements GrowiCommandProcessor {
+
+  async process(growiCommand: GrowiCommand, authorizeResult: AuthorizeResult, body: {[key:string]:string}): Promise<void> {
+
+    const { botToken } = authorizeResult;
 
-  async execSlashCommand(body:{[key:string]:string}):Promise<void> {
     // tmp use process.env
-    const client = new WebClient(process.env.SLACK_BOT_USER_OAUTH_TOKEN, { logLevel: LogLevel.DEBUG });
+    const client = new WebClient(botToken, { logLevel: LogLevel.DEBUG });
     await client.views.open({
       trigger_id: body.trigger_id,
       view: {

+ 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>
   );
 };

+ 4 - 23
src/client/js/components/Admin/SlackIntegration/CustomBotWithoutProxySettings.jsx

@@ -1,10 +1,9 @@
-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';
 
@@ -12,38 +11,20 @@ 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>
 
       <CustomBotWithoutProxyIntegrationCard
         siteName={siteName}
-        slackWSNameInWithoutProxy={slackWSNameInWithoutProxy}
+        slackWSNameInWithoutProxy={props.slackWSNameInWithoutProxy}
         isSetupSlackBot={props.isSetupSlackBot}
       />
 
@@ -55,7 +36,6 @@ const CustomBotWithoutProxySettings = (props) => {
           activeStep={botInstallationStep.CREATE_BOT}
         />
       </div>
-
     </>
   );
 };
@@ -72,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;

+ 2 - 2
src/server/routes/apiv3/slack-bot.js

@@ -36,7 +36,7 @@ module.exports = (crowi) => {
     return next();
   };
 
-  router.post('/', verificationRequestUrl, addSlackBotSigningSecret, verificationSlackRequest, verificationAccessToken, async(req, res) => {
+  router.post('/commands', verificationRequestUrl, addSlackBotSigningSecret, verificationSlackRequest, verificationAccessToken, async(req, res) => {
 
     // Send response immediately to avoid opelation_timeout error
     // See https://api.slack.com/apis/connections/events-api#the-events-api__responding-to-events
@@ -98,7 +98,7 @@ module.exports = (crowi) => {
     }
   };
 
-  router.post('/interactive', verificationRequestUrl, addSlackBotSigningSecret, verificationSlackRequest, async(req, res) => {
+  router.post('/interactions', verificationRequestUrl, addSlackBotSigningSecret, verificationSlackRequest, async(req, res) => {
 
     // Send response immediately to avoid opelation_timeout error
     // See https://api.slack.com/apis/connections/events-api#the-events-api__responding-to-events