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

Merge pull request #4069 from weseek/imprv/gw-6268-send-email-to-user-new

Imprv/gw 6268 send an email with inputValue
Yuki Takei 4 лет назад
Родитель
Сommit
0c82220093

+ 4 - 2
resource/locales/en_US/translation.json

@@ -846,13 +846,15 @@
   },
   "forgot_password":{
     "forgot_password": "Forgot Password?",
-    "send_email": "Send",
+    "send": "Send",
     "return_to_login": "Return to login",
     "reset_password": "Reset Password",
     "sign_in_instead": "Sign in instead",
     "password_reset_request_desc": "You can reset your password here.",
     "password_reset_excecution_desc": "Enter a new password",
     "new_password": "New Password",
-    "confirm_new_password": "Confirm the new password"
+    "confirm_new_password": "Confirm the new password",
+    "email_is_required": "Email is required",
+    "success_to_send_email": "Success to send email"
   }
 }

+ 4 - 2
resource/locales/ja_JP/translation.json

@@ -840,13 +840,15 @@
   },
   "forgot_password":{
     "forgot_password": "パスワードをお忘れですか?",
-    "send_email": "送信",
+    "send": "送信",
     "return_to_login": "ログイン画面に戻る",
     "reset_password": "パスワード リセット",
     "sign_in_instead": "ログインする",
     "password_reset_request_desc": "ここからパスワードリセットできます",
     "password_reset_excecution_desc": "新しいパスワードを入力してください",
     "new_password": "新しいパスワード",
-    "confirm_new_password": "新しいパスワードの確認"
+    "confirm_new_password": "新しいパスワードの確認",
+    "email_is_required": "メールを入力してください",
+    "success_to_send_email": "メールを送信しました"
   }
 }

+ 4 - 2
resource/locales/zh_CN/translation.json

@@ -851,13 +851,15 @@
   },
   "forgot_password":{
     "forgot_password": "忘记密码?",
-    "send_email": "发送",
+    "send": "发送",
     "return_to_login": "返回登录",
     "reset_password": "重设密码",
     "sign_in_instead": "改为登录",
     "password_reset_request_desc": "您可以在此处重置密码",
     "password_reset_excecution_desc": "输入新的密码",
     "new_password": "新密码",
-    "confirm_new_password": "确认新密码"
+    "confirm_new_password": "确认新密码",
+    "email_is_required": "电子邮件是必需的",
+    "success_to_send_email": "我发了一封电子邮件"
   }
 }

+ 42 - 6
src/client/js/components/PasswordResetRequestForm.jsx

@@ -1,20 +1,50 @@
-import React from 'react';
+import React, { useState } from 'react';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
+import { toastSuccess, toastError } from '../util/apiNotification';
+
+import AppContainer from '../services/AppContainer';
+import { withUnstatedContainers } from './UnstatedUtils';
 
 
 const PasswordResetRequestForm = (props) => {
-  const { t } = props;
+  const { t, appContainer } = props;
+  const [email, setEmail] = useState();
+
+  const changeEmail = (inputValue) => {
+    setEmail(inputValue);
+  };
+
+  const sendPasswordResetRequestMail = async(e) => {
+    e.preventDefault();
+    if (email == null) {
+      toastError('err', t('forgot_password.email_is_required'));
+      return;
+    }
+
+    try {
+      await appContainer.apiPost('/forgot-password', { email });
+      toastSuccess(t('forgot_password.success_to_send_email'));
+    }
+    catch (err) {
+      toastError('err', err);
+    }
+  };
 
   return (
-    <form role="form" className="form" method="post">
+    <form onSubmit={sendPasswordResetRequestMail}>
       <div className="form-group">
         <div className="input-group">
-          <input name="email" placeholder="E-mail Address" className="form-control" type="email" />
+          <input name="email" placeholder="E-mail Address" className="form-control" type="email" onChange={e => changeEmail(e.target.value)} />
         </div>
       </div>
       <div className="form-group">
-        <input name="reset-password-btn" className="btn btn-lg btn-primary btn-block" value={t('forgot_password.send_email')} type="submit" />
+        <button
+          className="btn btn-lg btn-primary btn-block"
+          type="submit"
+        >
+          {t('forgot_password.send')}
+        </button>
       </div>
       <a href="/login">
         <i className="icon-login mr-1"></i>{t('forgot_password.return_to_login')}
@@ -23,8 +53,14 @@ const PasswordResetRequestForm = (props) => {
   );
 };
 
+/**
+ * Wrapper component for using unstated
+ */
+const PasswordResetRequestFormWrapper = withUnstatedContainers(PasswordResetRequestForm, [AppContainer]);
+
 PasswordResetRequestForm.propTypes = {
   t: PropTypes.func.isRequired, //  i18next
+  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
 };
 
-export default withTranslation()(PasswordResetRequestForm);
+export default withTranslation()(PasswordResetRequestFormWrapper);

+ 5 - 1
src/client/js/nologin.jsx

@@ -82,11 +82,15 @@ if (loginFormElem) {
 
 // render PasswordResetRequestForm
 const passwordResetRequestFormElem = document.getElementById('password-reset-request-form');
+const appContainer = new AppContainer();
+appContainer.initApp();
 if (passwordResetRequestFormElem) {
 
   ReactDOM.render(
     <I18nextProvider i18n={i18n}>
-      <PasswordResetRequestForm />
+      <Provider inject={[appContainer]}>
+        <PasswordResetRequestForm />
+      </Provider>
     </I18nextProvider>,
     passwordResetRequestFormElem,
   );

+ 10 - 14
src/server/routes/forgot-password.js

@@ -18,11 +18,10 @@ module.exports = function(crowi, app) {
   };
 
 
-  async function sendPasswordResetEmail(i18n) {
-
+  async function sendPasswordResetEmail(email, i18n) {
     return mailService.send({
-      to: 'hoge@example.com',
-      subject: 'forgotPasswordMailTest',
+      to: email,
+      subject: 'Password Reset',
       template: path.join(crowi.localeDir, `${i18n}/notifications/passwordReset.txt`),
       // TODO: need to set appropriate values by GW-6828
       // vars: {
@@ -34,23 +33,20 @@ module.exports = function(crowi, app) {
   }
 
   api.post = async function(req, res) {
-    // TODO: using email getting by password reset request form by GW-6828
-    const email = 'foo@example.com';
+    const { email } = req.body;
+    const grobalLang = configManager.getConfig('crowi', 'app:globalLang');
+    const i18n = req.language || grobalLang;
+
     try {
-      const passwordResetOrderData = await PasswordResetOrder.createPasswordResetOrder(email);
-      res.send(ApiResponse.success({ passwordResetOrderData }));
+      await PasswordResetOrder.createPasswordResetOrder(email);
+      await sendPasswordResetEmail(email, i18n);
+      return res.json(ApiResponse.success());
     }
     catch (err) {
       const msg = 'Error occurred during password reset request procedure';
       logger.error(err);
       return res.json(ApiResponse.error(msg));
     }
-
-    const grobalLang = configManager.getConfig('crowi', 'app:globalLang');
-    const i18n = req.language || grobalLang;
-
-    await sendPasswordResetEmail(i18n);
-    return;
   };
 
 

+ 1 - 1
src/server/routes/index.js

@@ -177,7 +177,7 @@ module.exports = function(crowi, app) {
   app.post('/_api/hackmd.saveOnHackmd'   , accessTokenParser , loginRequiredStrictly , csrf, hackmd.validateForApi, hackmd.saveOnHackmd);
 
   app.get('/forgot-password', forgotPassword.forgotPassword);
-  app.post('/forgot-password', forgotPassword.api.post);
+  app.post('/_api/forgot-password', forgotPassword.api.post);
   // TODO: apply oneTimeToken to the link by GW−6856
   app.get('/forgot-password/hogeToken', forgotPassword.resetPassword);