Sfoglia il codice sorgente

Merge pull request #1659 from weseek/reactify/create-api-settings-component

Reactify/create api settings component
Yuki Takei 6 anni fa
parent
commit
2d4cbd8388

+ 107 - 0
src/client/js/components/Me/ApiSettings.jsx

@@ -0,0 +1,107 @@
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+
+import { toastSuccess, toastError } from '../../util/apiNotification';
+import { createSubscribedElement } from '../UnstatedUtils';
+
+import AppContainer from '../../services/AppContainer';
+import PersonalContainer from '../../services/PersonalContainer';
+
+
+class ApiSettings extends React.Component {
+
+  constructor(appContainer) {
+    super();
+
+    this.onClickSubmit = this.onClickSubmit.bind(this);
+  }
+
+  async onClickSubmit() {
+    const { t, appContainer, personalContainer } = this.props;
+
+    try {
+      await appContainer.apiv3Put('/personal-setting/api-token');
+
+      await personalContainer.retrievePersonalData();
+      toastSuccess(t('toaster.update_successed', { target: t('personal_settings.update_password') }));
+    }
+    catch (err) {
+      toastError(err);
+    }
+
+  }
+
+  render() {
+    const { t, personalContainer } = this.props;
+    return (
+      <React.Fragment>
+
+        <div className="mb-5 container-fluid">
+          <h2 className="border-bottom">{ t('API Token Settings') }</h2>
+        </div>
+
+        <div className="row mb-3">
+          <label htmlFor="apiToken" className="col-xs-3 text-right">{t('Current API Token')}</label>
+          <div className="col-xs-6">
+            {personalContainer.state.apiToken != null
+            ? (
+              <input
+                className="form-control"
+                type="text"
+                name="apiToken"
+                value={personalContainer.state.apiToken}
+                readOnly
+              />
+            )
+            : (
+              <p>
+                { t('page_me_apitoken.notice.apitoken_issued') }
+              </p>
+            )}
+          </div>
+        </div>
+
+
+        <div className="row">
+          <div className="col-xs-offset-3 col-xs-6">
+
+            <p className="alert alert-warning">
+              { t('page_me_apitoken.notice.update_token1') }<br />
+              { t('page_me_apitoken.notice.update_token2') }
+            </p>
+
+          </div>
+        </div>
+
+        <div className="row my-3">
+          <div className="col-xs-offset-4 col-xs-5">
+            <button
+              type="button"
+              className="btn btn-primary"
+              onClick={this.onClickSubmit}
+            >
+              {t('Update API Token')}
+            </button>
+          </div>
+        </div>
+
+      </React.Fragment>
+
+    );
+  }
+
+}
+
+const ApiSettingsWrapper = (props) => {
+  return createSubscribedElement(ApiSettings, props, [AppContainer, PersonalContainer]);
+};
+
+ApiSettings.propTypes = {
+  t: PropTypes.func.isRequired, // i18next
+  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
+  personalContainer: PropTypes.instanceOf(PersonalContainer).isRequired,
+};
+
+export default withTranslation()(ApiSettingsWrapper);

+ 2 - 1
src/client/js/components/Me/PersonalSettings.jsx

@@ -6,6 +6,7 @@ import { withTranslation } from 'react-i18next';
 import UserSettings from './UserSettings';
 import UserSettings from './UserSettings';
 import PasswordSettings from './PasswordSettings';
 import PasswordSettings from './PasswordSettings';
 import ExternalAccountLinkedMe from './ExternalAccountLinkedMe';
 import ExternalAccountLinkedMe from './ExternalAccountLinkedMe';
+import ApiSettings from './ApiSettings';
 
 
 class PersonalSettings extends React.Component {
 class PersonalSettings extends React.Component {
 
 
@@ -42,7 +43,7 @@ class PersonalSettings extends React.Component {
                 <PasswordSettings />
                 <PasswordSettings />
               </div>
               </div>
               <div id="apiToken" className="tab-pane" role="tabpanel">
               <div id="apiToken" className="tab-pane" role="tabpanel">
-                {/* TODO GW-1031 create component */}
+                <ApiSettings />
               </div>
               </div>
             </div>
             </div>
           </div>
           </div>

+ 2 - 0
src/client/js/services/PersonalContainer.js

@@ -25,6 +25,7 @@ export default class PersonalContainer extends Container {
       lang: 'en-US',
       lang: 'en-US',
       externalAccounts: [],
       externalAccounts: [],
       isPasswordSet: false,
       isPasswordSet: false,
+      apiToken: '',
     };
     };
 
 
   }
   }
@@ -50,6 +51,7 @@ export default class PersonalContainer extends Container {
         isEmailPublished: currentUser.isEmailPublished,
         isEmailPublished: currentUser.isEmailPublished,
         lang: currentUser.lang,
         lang: currentUser.lang,
         isPasswordSet: (currentUser.password != null),
         isPasswordSet: (currentUser.password != null),
+        apiToken: currentUser.apiToken,
       });
       });
     }
     }
     catch (err) {
     catch (err) {

+ 34 - 0
src/server/routes/apiv3/personal-setting.js

@@ -222,5 +222,39 @@ module.exports = (crowi) => {
 
 
   });
   });
 
 
+  /**
+   * @swagger
+   *
+   *    /personal-setting/api-token:
+   *      put:
+   *        tags: [PersonalSetting]
+   *        operationId: putUserApiToken
+   *        summary: /personal-setting/api-token
+   *        description: Update user api token
+   *        responses:
+   *          200:
+   *            description: succeded to update user api token
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    userData:
+   *                      type: object
+   *                      description: user data
+   */
+  router.put('/api-token', loginRequiredStrictly, csrf, async(req, res) => {
+    const { user } = req;
+
+    try {
+      const userData = await user.updateApiToken();
+      return res.apiv3({ userData });
+    }
+    catch (err) {
+      logger.error(err);
+      return res.apiv3Err('update-api-token-failed');
+    }
+
+  });
+
   return router;
   return router;
 };
 };

+ 0 - 2
src/server/routes/index.js

@@ -128,7 +128,6 @@ module.exports = function(crowi, app) {
   app.get('/admin/export/:fileName'             , loginRequiredStrictly , adminRequired ,admin.export.download);
   app.get('/admin/export/:fileName'             , loginRequiredStrictly , adminRequired ,admin.export.download);
 
 
   app.get('/me'                       , loginRequiredStrictly , me.index);
   app.get('/me'                       , loginRequiredStrictly , me.index);
-  app.get('/me/apiToken'              , loginRequiredStrictly , me.apiToken);
   app.post('/me'                      , loginRequiredStrictly , csrf , form.me.user , me.index);
   app.post('/me'                      , loginRequiredStrictly , csrf , form.me.user , me.index);
   // external-accounts
   // external-accounts
   app.get('/me/external-accounts'                         , loginRequiredStrictly , me.externalAccounts.list);
   app.get('/me/external-accounts'                         , loginRequiredStrictly , me.externalAccounts.list);
@@ -136,7 +135,6 @@ module.exports = function(crowi, app) {
   app.post('/me/external-accounts/associateLdap'          , loginRequiredStrictly , form.login , me.externalAccounts.associateLdap);
   app.post('/me/external-accounts/associateLdap'          , loginRequiredStrictly , form.login , me.externalAccounts.associateLdap);
 
 
   app.post('/me/imagetype'            , form.me.imagetype         , loginRequiredStrictly , me.imagetype);
   app.post('/me/imagetype'            , form.me.imagetype         , loginRequiredStrictly , me.imagetype);
-  app.post('/me/apiToken'             , form.me.apiToken          , loginRequiredStrictly , me.apiToken);
 
 
   app.get('/:id([0-9a-z]{24})'       , loginRequired , page.redirector);
   app.get('/:id([0-9a-z]{24})'       , loginRequired , page.redirector);
   app.get('/_r/:id([0-9a-z]{24})'    , loginRequired , page.redirector); // alias
   app.get('/_r/:id([0-9a-z]{24})'    , loginRequired , page.redirector); // alias

+ 0 - 22
src/server/routes/me.js

@@ -254,28 +254,6 @@ module.exports = function(crowi, app) {
     })(req, res, () => {});
     })(req, res, () => {});
   };
   };
 
 
-  actions.apiToken = function(req, res) {
-    const userData = req.user;
-
-    if (req.method === 'POST' && req.form.isValid) {
-      userData.updateApiToken()
-        .then((userData) => {
-          req.flash('successMessage', 'API Token updated');
-          return res.redirect('/me/apiToken');
-        })
-        .catch((err) => {
-        // req.flash('successMessage',);
-          req.form.errors.push('Failed to update API Token');
-          return res.render('me/api_token', {
-          });
-        });
-    }
-    else {
-      return res.render('me/api_token', {
-      });
-    }
-  };
-
   actions.updates = function(req, res) {
   actions.updates = function(req, res) {
     res.render('me/update', {
     res.render('me/update', {
     });
     });