Browse Source

Merge pull request #1438 from weseek/reactify-admin/create-apiV3-update-google-setting

Reactify admin/create api v3 update google setting
Yuki Takei 6 years ago
parent
commit
0534903a51

+ 2 - 1
resource/locales/en-US/translation.json

@@ -557,7 +557,8 @@
         "register_2": "Create Project if no projects exist",
         "register_2": "Create Project if no projects exist",
         "register_3": "Create Credentials → OAuth client ID → Select \"Web application\"",
         "register_3": "Create Credentials → OAuth client ID → Select \"Web application\"",
         "register_4": "Register your OAuth App with one of Authorized redirect URIs as <code>{{url}}</code>",
         "register_4": "Register your OAuth App with one of Authorized redirect URIs as <code>{{url}}</code>",
-        "register_5": "Copy and paste your ClientID and Client Secret above"
+        "register_5": "Copy and paste your ClientID and Client Secret above",
+        "updated_google": "Succeeded to update Google OAuth setting"
       },
       },
       "Facebook": {
       "Facebook": {
         "name": "Facebook OAuth"
         "name": "Facebook OAuth"

+ 2 - 1
resource/locales/ja/translation.json

@@ -552,7 +552,8 @@
         "register_2": "プロジェクトがない場合はプロジェクトを作成",
         "register_2": "プロジェクトがない場合はプロジェクトを作成",
         "register_3": "認証情報を作成 &rightarrow; OAuthクライアントID &rightarrow; ウェブアプリケーションを選択",
         "register_3": "認証情報を作成 &rightarrow; OAuthクライアントID &rightarrow; ウェブアプリケーションを選択",
         "register_4": "承認済みのリダイレクトURIを<code>{{url}}</code>としてGrowiを登録",
         "register_4": "承認済みのリダイレクトURIを<code>{{url}}</code>としてGrowiを登録",
-        "register_5": "上記フォームにクライアントIDとクライアントシークレットを入力"
+        "register_5": "上記フォームにクライアントIDとクライアントシークレットを入力",
+        "updated_google": "Google OAuth を更新しました"
       },
       },
       "Facebook": {
       "Facebook": {
         "name": "Facebook OAuth"
         "name": "Facebook OAuth"

+ 1 - 1
src/client/js/components/Admin/Security/GithubSecuritySetting.jsx

@@ -166,7 +166,7 @@ class GithubSecurityManagement extends React.Component {
         )}
         )}
 
 
         <div className="row my-3">
         <div className="row my-3">
-          <div className="col-xs-offset-4 col-xs-5">
+          <div className="col-xs-offset-3 col-xs-5">
             <div className="btn btn-primary" disabled={this.state.retrieveError != null} onClick={this.onClickSubmit}>{ t('Update') }</div>
             <div className="btn btn-primary" disabled={this.state.retrieveError != null} onClick={this.onClickSubmit}>{ t('Update') }</div>
           </div>
           </div>
         </div>
         </div>

+ 54 - 2
src/client/js/components/Admin/Security/GoogleSecuritySetting.jsx

@@ -2,15 +2,55 @@
 import React from 'react';
 import React from 'react';
 import PropTypes from 'prop-types';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 import { withTranslation } from 'react-i18next';
+import loggerFactory from '@alias/logger';
 
 
 import { createSubscribedElement } from '../../UnstatedUtils';
 import { createSubscribedElement } from '../../UnstatedUtils';
+import { toastSuccess, toastError } from '../../../util/apiNotification';
 
 
 import AppContainer from '../../../services/AppContainer';
 import AppContainer from '../../../services/AppContainer';
 import AdminGeneralSecurityContainer from '../../../services/AdminGeneralSecurityContainer';
 import AdminGeneralSecurityContainer from '../../../services/AdminGeneralSecurityContainer';
 import AdminGoogleSecurityContainer from '../../../services/AdminGoogleSecurityContainer';
 import AdminGoogleSecurityContainer from '../../../services/AdminGoogleSecurityContainer';
 
 
+const logger = loggerFactory('growi:security:AdminGoogleSecurityContainer');
+
 class GoogleSecurityManagement extends React.Component {
 class GoogleSecurityManagement extends React.Component {
 
 
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      retrieveError: null,
+    };
+
+    this.onClickSubmit = this.onClickSubmit.bind(this);
+  }
+
+  async componentDidMount() {
+    const { adminGoogleSecurityContainer } = this.props;
+
+    try {
+      await adminGoogleSecurityContainer.retrieveSecurityData();
+    }
+    catch (err) {
+      toastError(err);
+      this.setState({ retrieveError: err });
+      logger.error(err);
+    }
+  }
+
+  async onClickSubmit() {
+    const { t, adminGoogleSecurityContainer } = this.props;
+
+    try {
+      await adminGoogleSecurityContainer.updateGoogleSetting();
+      toastSuccess(t('security_setting.OAuth.Google.updated_google'));
+    }
+    catch (err) {
+      toastError(err);
+      logger.error(err);
+    }
+  }
+
   render() {
   render() {
     const { t, adminGeneralSecurityContainer, adminGoogleSecurityContainer } = this.props;
     const { t, adminGeneralSecurityContainer, adminGoogleSecurityContainer } = this.props;
     return (
     return (
@@ -21,6 +61,12 @@ class GoogleSecurityManagement extends React.Component {
           { t('security_setting.OAuth.Google.name') } { t('security_setting.configuration') }
           { t('security_setting.OAuth.Google.name') } { t('security_setting.configuration') }
         </h2>
         </h2>
 
 
+        {this.state.retrieveError != null && (
+        <div className="alert alert-danger">
+          <p>{t('Error occurred')} : {this.state.err}</p>
+        </div>
+        )}
+
         <div className="row mb-5">
         <div className="row mb-5">
           <strong className="col-xs-3 text-right">{ t('security_setting.OAuth.Google.name') }</strong>
           <strong className="col-xs-3 text-right">{ t('security_setting.OAuth.Google.name') }</strong>
           <div className="col-xs-6 text-left">
           <div className="col-xs-6 text-left">
@@ -71,7 +117,7 @@ class GoogleSecurityManagement extends React.Component {
                   className="form-control"
                   className="form-control"
                   type="text"
                   type="text"
                   name="googleClientId"
                   name="googleClientId"
-                  value={adminGoogleSecurityContainer.state.googleClientId}
+                  defaultValue={adminGoogleSecurityContainer.state.googleClientId}
                   onChange={e => adminGoogleSecurityContainer.changeGoogleClientId(e.target.value)}
                   onChange={e => adminGoogleSecurityContainer.changeGoogleClientId(e.target.value)}
                 />
                 />
                 <p className="help-block">
                 <p className="help-block">
@@ -87,7 +133,7 @@ class GoogleSecurityManagement extends React.Component {
                   className="form-control"
                   className="form-control"
                   type="text"
                   type="text"
                   name="googleClientSecret"
                   name="googleClientSecret"
-                  value={adminGoogleSecurityContainer.state.googleClientSecret}
+                  defaultValue={adminGoogleSecurityContainer.state.googleClientSecret}
                   onChange={e => adminGoogleSecurityContainer.changeGoogleClientSecret(e.target.value)}
                   onChange={e => adminGoogleSecurityContainer.changeGoogleClientSecret(e.target.value)}
                 />
                 />
                 <p className="help-block">
                 <p className="help-block">
@@ -119,6 +165,12 @@ class GoogleSecurityManagement extends React.Component {
           </React.Fragment>
           </React.Fragment>
         )}
         )}
 
 
+        <div className="row my-3">
+          <div className="col-xs-offset-3 col-xs-5">
+            <button type="button" className="btn btn-primary" disabled={this.state.retrieveError != null} onClick={this.onClickSubmit}>{ t('Update') }</button>
+          </div>
+        </div>
+
         <hr />
         <hr />
 
 
         <div style={{ minHeight: '300px' }}>
         <div style={{ minHeight: '300px' }}>

+ 1 - 1
src/client/js/components/Admin/Security/TwitterSecuritySetting.jsx

@@ -166,7 +166,7 @@ class TwitterSecurityManagement extends React.Component {
         )}
         )}
 
 
         <div className="row my-3">
         <div className="row my-3">
-          <div className="col-xs-offset-4 col-xs-5">
+          <div className="col-xs-offset-3 col-xs-5">
             <button type="button" className="btn btn-primary" disabled={this.state.retrieveError != null} onClick={this.onClickSubmit}>{ t('Update') }</button>
             <button type="button" className="btn btn-primary" disabled={this.state.retrieveError != null} onClick={this.onClickSubmit}>{ t('Update') }</button>
           </div>
           </div>
         </div>
         </div>

+ 37 - 6
src/client/js/services/AdminGoogleSecurityContainer.js

@@ -1,6 +1,9 @@
 import { Container } from 'unstated';
 import { Container } from 'unstated';
 
 
 import loggerFactory from '@alias/logger';
 import loggerFactory from '@alias/logger';
+import { pathUtils } from 'growi-commons';
+
+import urljoin from 'url-join';
 
 
 // eslint-disable-next-line no-unused-vars
 // eslint-disable-next-line no-unused-vars
 const logger = loggerFactory('growi:security:AdminGoogleSecurityContainer');
 const logger = loggerFactory('growi:security:AdminGoogleSecurityContainer');
@@ -17,19 +20,26 @@ export default class AdminGoogleSecurityContainer extends Container {
     this.appContainer = appContainer;
     this.appContainer = appContainer;
 
 
     this.state = {
     this.state = {
-      // TODO GW-583 set value
-      appSiteUrl: '',
+      callbackUrl: urljoin(pathUtils.removeTrailingSlash(appContainer.config.crowi.url), '/passport/google/callback'),
       googleClientId: '',
       googleClientId: '',
       googleClientSecret: '',
       googleClientSecret: '',
-      isSameUsernameTreatedAsIdenticalUser: true,
+      isSameUsernameTreatedAsIdenticalUser: false,
     };
     };
 
 
-    this.init();
 
 
   }
   }
 
 
-  init() {
-    // TODO GW-583 fetch config value with api
+  /**
+   * retrieve security data
+   */
+  async retrieveSecurityData() {
+    const response = await this.appContainer.apiv3.get('/security-setting/');
+    const { googleOAuth } = response.data.securityParams;
+    this.setState({
+      googleClientId: googleOAuth.googleClientId || '',
+      googleClientSecret: googleOAuth.googleClientSecret || '',
+      isSameUsernameTreatedAsIdenticalUser: googleOAuth.isSameUsernameTreatedAsIdenticalUser || false,
+    });
   }
   }
 
 
   /**
   /**
@@ -60,4 +70,25 @@ export default class AdminGoogleSecurityContainer extends Container {
     this.setState({ isSameUsernameTreatedAsIdenticalUser: !this.state.isSameUsernameTreatedAsIdenticalUser });
     this.setState({ isSameUsernameTreatedAsIdenticalUser: !this.state.isSameUsernameTreatedAsIdenticalUser });
   }
   }
 
 
+  /**
+   * Update googleSetting
+   */
+  async updateGoogleSetting() {
+
+    const response = await this.appContainer.apiv3.put('/security-setting/google-oauth', {
+      googleClientId: this.state.googleClientId,
+      googleClientSecret: this.state.googleClientSecret,
+      isSameUsernameTreatedAsIdenticalUser: this.state.isSameUsernameTreatedAsIdenticalUser,
+    });
+
+    const { securitySettingParams } = response.data;
+
+    this.setState({
+      googleClientId: securitySettingParams.googleClientId,
+      googleClientSecret: securitySettingParams.googleClientSecret,
+      isSameUsernameTreatedAsIdenticalUser: securitySettingParams.isSameUsernameTreatedAsIdenticalUser,
+    });
+    return response;
+  }
+
 }
 }

+ 68 - 2
src/server/routes/apiv3/security-setting.js

@@ -19,6 +19,11 @@ const validator = {
     body('hideRestrictedByOwner').isBoolean(),
     body('hideRestrictedByOwner').isBoolean(),
     body('hideRestrictedByGroup').isBoolean(),
     body('hideRestrictedByGroup').isBoolean(),
   ],
   ],
+  googleOAuth: [
+    body('googleClientId').isString(),
+    body('googleClientSecret').isString(),
+    body('isSameUsernameTreatedAsIdenticalUser').isBoolean(),
+  ],
   githubOAuth: [
   githubOAuth: [
     body('githubClientId').isString(),
     body('githubClientId').isString(),
     body('githubClientSecret').isString(),
     body('githubClientSecret').isString(),
@@ -79,6 +84,17 @@ const validator = {
  *              isSameUsernameTreatedAsIdenticalUser
  *              isSameUsernameTreatedAsIdenticalUser
  *                type: boolean
  *                type: boolean
  *                description: local account automatically linked the email matched
  *                description: local account automatically linked the email matched
+ *          GoogleOAuthSetting:
+ *            type:object
+ *              googleClientId:
+ *                type: string
+ *                description: key of comsumer
+ *              googleClientSecret:
+ *                type: string
+ *                description: password of comsumer
+ *              isSameUsernameTreatedAsIdenticalUser
+ *                type: boolean
+ *                description: local account automatically linked the email matched
  *          TwitterOAuthSetting:
  *          TwitterOAuthSetting:
  *            type:object
  *            type:object
  *              twitterConsumerKey:
  *              twitterConsumerKey:
@@ -119,9 +135,15 @@ module.exports = (crowi) => {
 
 
     const securityParams = {
     const securityParams = {
       generalAuth: {
       generalAuth: {
+        isGoogleOAuthEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-google:isEnabled'),
         isGithubOAuthEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-github:isEnabled'),
         isGithubOAuthEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-github:isEnabled'),
         isTwitterOAuthEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-twitter:isEnabled'),
         isTwitterOAuthEnabled: await crowi.configManager.getConfig('crowi', 'security:passport-twitter:isEnabled'),
       },
       },
+      googleOAuth: {
+        googleClientId: await crowi.configManager.getConfig('crowi', 'security:passport-google:clientId'),
+        googleClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-google:clientSecret'),
+        isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-google:isSameUsernameTreatedAsIdenticalUser'),
+      },
       githubOAuth: {
       githubOAuth: {
         githubClientId: await crowi.configManager.getConfig('crowi', 'security:passport-github:clientId'),
         githubClientId: await crowi.configManager.getConfig('crowi', 'security:passport-github:clientId'),
         githubClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-github:clientSecret'),
         githubClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-github:clientSecret'),
@@ -198,6 +220,50 @@ module.exports = (crowi) => {
     }
     }
   });
   });
 
 
+  /**
+   * @swagger
+   *
+   *    /security-setting/google-oauth:
+   *      put:
+   *        tags: [SecuritySetting]
+   *        description: Update google OAuth
+   *        requestBody:
+   *          required: true
+   *          content:
+   *            application/json:
+   *              schema:
+   *                $ref: '#/components/schemas/SecurityParams/GoogleOAuthSetting'
+   *        responses:
+   *          200:
+   *            description: Succeeded to google OAuth
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  $ref: '#/components/schemas/SecurityParams/GoogleOAuthSetting'
+   */
+  router.put('/google-oauth', loginRequiredStrictly, adminRequired, csrf, validator.googleOAuth, ApiV3FormValidator, async(req, res) => {
+    const requestParams = {
+      'security:passport-google:clientId': req.body.googleClientId,
+      'security:passport-google:clientSecret': req.body.googleClientSecret,
+      'security:passport-google:isSameUsernameTreatedAsIdenticalUser': req.body.isSameUsernameTreatedAsIdenticalUser,
+    };
+
+    try {
+      await crowi.configManager.updateConfigsInTheSameNamespace('crowi', requestParams);
+      const securitySettingParams = {
+        googleClientId: await crowi.configManager.getConfig('crowi', 'security:passport-google:clientId'),
+        googleClientSecret: await crowi.configManager.getConfig('crowi', 'security:passport-google:clientSecret'),
+        isSameUsernameTreatedAsIdenticalUser: await crowi.configManager.getConfig('crowi', 'security:passport-google:isSameUsernameTreatedAsIdenticalUser'),
+      };
+      return res.apiv3({ securitySettingParams });
+    }
+    catch (err) {
+      const msg = 'Error occurred in updating googleOAuth';
+      logger.error('Error', err);
+      return res.apiv3Err(new ErrorV3(msg, 'update-googleOAuth-failed'));
+    }
+  });
+
   /**
   /**
    * @swagger
    * @swagger
    *
    *
@@ -213,7 +279,7 @@ module.exports = (crowi) => {
    *                $ref: '#/components/schemas/SecurityParams/GitHubOAuthSetting'
    *                $ref: '#/components/schemas/SecurityParams/GitHubOAuthSetting'
    *        responses:
    *        responses:
    *          200:
    *          200:
-   *            description: Succeeded to update function
+   *            description: Succeeded to github OAuth
    *            content:
    *            content:
    *              application/json:
    *              application/json:
    *                schema:
    *                schema:
@@ -257,7 +323,7 @@ module.exports = (crowi) => {
    *                $ref: '#/components/schemas/SecurityParams/TwitterOAuthSetting'
    *                $ref: '#/components/schemas/SecurityParams/TwitterOAuthSetting'
    *        responses:
    *        responses:
    *          200:
    *          200:
-   *            description: Succeeded to update function
+   *            description: Succeeded to update twitter OAuth
    *            content:
    *            content:
    *              application/json:
    *              application/json:
    *                schema:
    *                schema: