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

Merge pull request #3583 from weseek/feat/5456-show-access-token

Feat/5456 show access token
深瀬スティーヴン 5 лет назад
Родитель
Сommit
bdf22ad12b

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

@@ -254,6 +254,7 @@
   },
   "slack_integration": {
     "bot_reset_successful": "Bot settings have been reset.",
+    "copied_to_clipboard": "Copied to clipboard",
     "modal": {
       "warning": "Warning",
       "sure_change_bot_type": "Are you sure you want to change the bot type?",

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

@@ -252,6 +252,7 @@
   },
   "slack_integration": {
     "bot_reset_successful": "Botの設定を消去しました。",
+    "copied_to_clipboard": "クリップボードにコピーされました。",
     "modal": {
       "warning": "注意",
       "sure_change_bot_type": "Botの種類を変更しますか?",

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

@@ -262,6 +262,7 @@
   },
   "slack_integration": {
     "bot_reset_successful": "删除了BOT设置。",
+    "copied_to_clipboard": "它已复制到剪贴板。",
     "modal": {
       "warning": "警告",
       "sure_change_bot_type": "您确定要更改设置吗?",

+ 51 - 25
src/client/js/components/Admin/SlackIntegration/AccessTokenSettings.jsx

@@ -1,39 +1,65 @@
-/* eslint-disable no-console */
 import React from 'react';
+import PropTypes from 'prop-types';
 import { useTranslation } from 'react-i18next';
+import { CopyToClipboard } from 'react-copy-to-clipboard';
+import { toastSuccess } from '../../../util/apiNotification';
 
-function AccessTokenSettings() {
-
+const AccessTokenSettings = (props) => {
   const { t } = useTranslation('admin');
-  function discardHandler() {
-    console.log('Discard button pressed');
-  }
 
-  function generateHandler() {
-    console.log('Generate button pressed');
-  }
+  const onClickDiscardButton = () => {
+    if (props.onClickDiscardButton != null) {
+      props.onClickDiscardButton();
+    }
+  };
+
+  const onClickGenerateToken = () => {
+    if (props.onClickGenerateToken != null) {
+      props.onClickGenerateToken();
+    }
+  };
+
+  const accessToken = props.accessToken ? props.accessToken : '';
 
   return (
-    <>
-      <div className="form-group row my-5">
-        <label className="text-left text-md-right col-md-3 col-form-label">Access Token</label>
-        <div className="col-md-6">
-          <input className="form-control" type="text" placeholder="access-token" />
+    <div className="row">
+      <div className="col-lg-12">
+
+        <h2 className="admin-setting-header">Access Token</h2>
+
+        <div className="form-group row my-5">
+          <label className="text-left text-md-right col-md-3 col-form-label">Access Token</label>
+          <div className="col-md-6">
+            {accessToken.length === 0 ? (
+              <input className="form-control" type="text" value={accessToken} readOnly />
+            ) : (
+              <CopyToClipboard text={accessToken} onCopy={() => toastSuccess(t('slack_integration.copied_to_clipboard'))}>
+                <input className="form-control" type="text" value={accessToken} readOnly />
+              </CopyToClipboard>
+            )}
+          </div>
         </div>
-      </div>
 
-      <div className="row">
-        <div className="mx-auto">
-          <button type="button" className="btn btn-outline-secondary text-nowrap mx-1" onClick={discardHandler}>
-            {t('slack_integration.access_token_settings.discard')}
-          </button>
-          <button type="button" className="btn btn-primary text-nowrap mx-1" onClick={generateHandler}>
-            {t('slack_integration.access_token_settings.generate')}
-          </button>
+        <div className="row">
+          <div className="mx-auto">
+            <button type="button" className="btn btn-outline-secondary text-nowrap mx-1" onClick={onClickDiscardButton} disabled={accessToken.length === 0}>
+              {t('slack_integration.access_token_settings.discard')}
+            </button>
+            <button type="button" className="btn btn-primary text-nowrap mx-1" onClick={onClickGenerateToken}>
+              {t('slack_integration.access_token_settings.generate')}
+            </button>
+          </div>
         </div>
+
       </div>
-    </>
+    </div>
   );
-}
+};
+
+AccessTokenSettings.propTypes = {
+  accessToken: PropTypes.string,
+  onClickDiscardButton: PropTypes.func,
+  onClickGenerateToken: PropTypes.func,
+};
 
 export default AccessTokenSettings;

+ 38 - 17
src/client/js/components/Admin/SlackIntegration/SlackIntegration.jsx

@@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next';
 import AppContainer from '../../../services/AppContainer';
 import { withUnstatedContainers } from '../../UnstatedUtils';
 import { toastSuccess, toastError } from '../../../util/apiNotification';
+
 import AccessTokenSettings from './AccessTokenSettings';
 import OfficialBotSettings from './OfficialBotSettings';
 import CustomBotWithoutProxySettings from './CustomBotWithoutProxySettings';
@@ -16,12 +17,14 @@ const SlackIntegration = (props) => {
   const { t } = useTranslation();
   const [currentBotType, setCurrentBotType] = useState(null);
   const [selectedBotType, setSelectedBotType] = useState(null);
+  const [accessToken, setAccessToken] = useState('');
 
   const fetchData = useCallback(async() => {
     try {
       const response = await appContainer.apiv3.get('slack-integration/');
-      const { currentBotType } = response.data.slackBotSettingParams;
+      const { currentBotType, accessToken } = response.data.slackBotSettingParams;
       setCurrentBotType(currentBotType);
+      setAccessToken(accessToken);
     }
     catch (err) {
       toastError(err);
@@ -43,11 +46,11 @@ const SlackIntegration = (props) => {
     setSelectedBotType(clickedBotType);
   };
 
-  const handleCancelBotChange = () => {
+  const cancelBotChangeHandler = () => {
     setSelectedBotType(null);
   };
 
-  const handleChangeCurrentBotSettings = async() => {
+  const changeCurrentBotSettingsHandler = async() => {
     try {
       const res = await appContainer.apiv3.put('slack-integration/custom-bot-without-proxy', {
         slackSigningSecret: '',
@@ -63,6 +66,27 @@ const SlackIntegration = (props) => {
     }
   };
 
+  const generateTokenHandler = async() => {
+    try {
+      await appContainer.apiv3.put('slack-integration/access-token');
+      fetchData();
+    }
+    catch (err) {
+      toastError(err);
+    }
+  };
+
+  const discardTokenHandler = async() => {
+    try {
+      await appContainer.apiv3.delete('slack-integration/access-token');
+      fetchData();
+      toastSuccess(t('admin:slack_integration.bot_reset_successful'));
+    }
+    catch (err) {
+      toastError(err);
+    }
+  };
+
   let settingsComponent = null;
 
   switch (currentBotType) {
@@ -81,20 +105,17 @@ const SlackIntegration = (props) => {
 
   return (
     <>
-      <div className="container">
-        <ConfirmBotChangeModal
-          isOpen={selectedBotType != null}
-          onConfirmClick={handleChangeCurrentBotSettings}
-          onCancelClick={handleCancelBotChange}
-        />
-      </div>
-
-      <div className="row">
-        <div className="col-lg-12">
-          <h2 className="admin-setting-header">Access Token</h2>
-          <AccessTokenSettings />
-        </div>
-      </div>
+      <ConfirmBotChangeModal
+        isOpen={selectedBotType != null}
+        onConfirmClick={changeCurrentBotSettingsHandler}
+        onCancelClick={cancelBotChangeHandler}
+      />
+
+      <AccessTokenSettings
+        accessToken={accessToken}
+        onClickDiscardButton={discardTokenHandler}
+        onClickGenerateToken={generateTokenHandler}
+      />
 
       <div className="row my-5">
         <div className="card-deck mx-auto">

+ 1 - 0
src/server/routes/apiv3/slack-integration.js

@@ -87,6 +87,7 @@ module.exports = (crowi) => {
    */
   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: {

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

@@ -410,6 +410,12 @@ const ENV_VAR_NAME_TO_CONFIG_INFO = {
     type:    TYPES.STRING,
     default: null,
   },
+  SLACK_BOT_ACCESS_TOKEN: {
+    ns:      'crowi',
+    key:     'slackbot:access-token',
+    type:    TYPES.STRING,
+    default: null,
+  },
   SLACK_BOT_TYPE: {
     ns:      'crowi',
     key:     'slackbot:currentBotType', // 'official-bot' || 'custom-bot-without-proxy' || 'custom-bot-with-proxy'