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

123395 send new password by email

soumaeda 2 лет назад
Родитель
Сommit
5e71d6b6f0

+ 1 - 4
apps/app/public/static/locales/en_US/admin.json

@@ -758,10 +758,7 @@
       "send_new_password": "Please send the new password to the user.",
       "send_new_password": "Please send the new password to the user.",
       "target_user": "Target User",
       "target_user": "Target User",
       "new_password": "New Password",
       "new_password": "New Password",
-      "send_password_email": "Send the password to user",
-      "mail_setting_link":"<i class='icon-settings mr-2'></i><a href='/admin/app'>Email settings</a>",
-      "show_password": "Click to show password",
-      "hide_password": "hide"
+      "mail_setting_link":"<i class='icon-settings mr-2'></i><a href='/admin/app'>Email settings</a>"
     },
     },
     "external_account": "External Account Management",
     "external_account": "External Account Management",
     "external_accounts":"External accounts",
     "external_accounts":"External accounts",

+ 1 - 4
apps/app/public/static/locales/ja_JP/admin.json

@@ -766,10 +766,7 @@
       "send_new_password": "新規発行したパスワードを、対象ユーザーへ連絡してください。",
       "send_new_password": "新規発行したパスワードを、対象ユーザーへ連絡してください。",
       "target_user": "対象ユーザー",
       "target_user": "対象ユーザー",
       "new_password": "新しいパスワード",
       "new_password": "新しいパスワード",
-      "send_password_email": "メールを送信する",
-      "mail_setting_link": "<i class='icon-settings mr-2'></i><a href='/admin/app'>メールの設定</a>",
-      "show_password": "クリックしてパスワードを表示",
-      "hide_password": "非表示"
+      "mail_setting_link": "<i class='icon-settings mr-2'></i><a href='/admin/app'>メールの設定</a>"
     },
     },
     "external_account": "外部アカウントの管理",
     "external_account": "外部アカウントの管理",
     "external_accounts": "外部アカウント",
     "external_accounts": "外部アカウント",

+ 1 - 4
apps/app/public/static/locales/zh_CN/admin.json

@@ -766,10 +766,7 @@
       "send_new_password": "Please send the new password to the user.",
       "send_new_password": "Please send the new password to the user.",
       "target_user": "Target User",
       "target_user": "Target User",
       "new_password": "New Password",
       "new_password": "New Password",
-      "send_password_email": "Send the password to user",
-      "mail_setting_link":"<i class='icon-settings mr-2'></i><a href='/admin/app'>Email settings</a>",
-      "show_password": "Click to show password",
-      "hide_password": "hide"
+      "mail_setting_link":"<i class='icon-settings mr-2'></i><a href='/admin/app'>Email settings</a>"
     },
     },
     "external_account": "外部账户管理",
     "external_account": "外部账户管理",
     "external_accounts": "外部账户",
     "external_accounts": "外部账户",

+ 69 - 20
apps/app/src/components/Admin/Users/PasswordResetModal.jsx

@@ -6,6 +6,7 @@ import {
   Modal, ModalHeader, ModalBody, ModalFooter, Collapse,
   Modal, ModalHeader, ModalBody, ModalFooter, Collapse,
 } from 'reactstrap';
 } from 'reactstrap';
 
 
+import AdminUsersContainer from '~/client/services/AdminUsersContainer';
 import { apiv3Put } from '~/client/util/apiv3-client';
 import { apiv3Put } from '~/client/util/apiv3-client';
 import { toastSuccess, toastError } from '~/client/util/toastr';
 import { toastSuccess, toastError } from '~/client/util/toastr';
 import { useIsMailerSetup } from '~/stores/context';
 import { useIsMailerSetup } from '~/stores/context';
@@ -25,6 +26,7 @@ class PasswordResetModal extends React.Component {
     };
     };
 
 
     this.resetPassword = this.resetPassword.bind(this);
     this.resetPassword = this.resetPassword.bind(this);
+    this.onClickSendNewPasswordButton = this.onClickSendNewPasswordButton.bind(this);
     this.toggle = this.toggle.bind(this);
     this.toggle = this.toggle.bind(this);
   }
   }
 
 
@@ -62,7 +64,6 @@ class PasswordResetModal extends React.Component {
 
 
   returnModalBodyAfterReset() {
   returnModalBodyAfterReset() {
     const { t, userForPasswordResetModal } = this.props;
     const { t, userForPasswordResetModal } = this.props;
-
     return (
     return (
       <>
       <>
         <p className="text-danger">{t('user_management.reset_password_modal.password_reset_message')}</p>
         <p className="text-danger">{t('user_management.reset_password_modal.password_reset_message')}</p>
@@ -70,24 +71,14 @@ class PasswordResetModal extends React.Component {
           {t('user_management.reset_password_modal.target_user')}: <code>{userForPasswordResetModal.email}</code>
           {t('user_management.reset_password_modal.target_user')}: <code>{userForPasswordResetModal.email}</code>
         </p>
         </p>
         <p>
         <p>
-          {t('user_management.reset_password_modal.new_password')}:
-          <button className="btn btn-secondary mx-2 px-1 py-0" size="sm" onClick={this.toggle} aria-expanded="false">
-            {this.state.collapse ? t('user_management.reset_password_modal.hide_password') : t('user_management.reset_password_modal.show_password') }
-          </button>
-          {this.state.collapse && (
-            <Collapse isOpen={this.state.collapse}>
-              <code>
-                {this.state.temporaryPassword}
-              </code>
-            </Collapse>
-          )}
+          {t('user_management.reset_password_modal.new_password')}: <code>{this.state.temporaryPassword}</code>
         </p>
         </p>
       </>
       </>
     );
     );
   }
   }
 
 
   returnModalFooterBeforeReset() {
   returnModalFooterBeforeReset() {
-    const { t, isMailerSetup } = this.props;
+    const { t } = this.props;
     return (
     return (
       <button type="submit" className="btn btn-danger" onClick={this.resetPassword}>
       <button type="submit" className="btn btn-danger" onClick={this.resetPassword}>
         {t('user_management.reset_password')}
         {t('user_management.reset_password')}
@@ -96,20 +87,76 @@ class PasswordResetModal extends React.Component {
   }
   }
 
 
   returnModalFooterAfterReset() {
   returnModalFooterAfterReset() {
-    const { t } = this.props;
-
+    const { t, isMailerSetup, userForPasswordResetModal } = this.props;
+
+    if (!isMailerSetup) {
+      return (
+        <>
+          <div>
+            <label className="form-text text-muted" dangerouslySetInnerHTML={{ __html: t('admin:mailer_setup_required') }} />
+          </div>
+          <div>
+            <button type="submit" className="btn btn-primary" onClick={this.onClickSendNewPasswordButton} disabled={!isMailerSetup}>
+              {t('Send')}
+            </button>
+          </div>
+          <div>
+            <button type="submit" className="btn btn-danger" onClick={this.props.onClose}>
+              {t('Close')}
+            </button>
+          </div>
+        </>
+      );
+    }
     return (
     return (
-      <button type="submit" className="btn btn-primary" onClick={this.props.onClose}>
-        {t('Close')}
-      </button>
+      <>
+        <p className="mb-4 mt-1">To:</p>
+        <div className="mr-3">
+          <p className="mb-0">{userForPasswordResetModal.username}</p>
+          <p className="mb-0">{userForPasswordResetModal.email}</p>
+        </div>
+        <div>
+          <button type="submit" className="btn btn-primary" onClick={this.onClickSendNewPasswordButton} disabled={!isMailerSetup}>
+            {t('Send')}
+          </button>
+        </div>
+        <div>
+          <button type="submit" className="btn btn-danger" onClick={this.props.onClose}>
+            {t('Close')}
+          </button>
+        </div>
+      </>
     );
     );
   }
   }
 
 
+  async onClickSendNewPasswordButton() {
+
+    const {
+      userForPasswordResetModal,
+    } = this.props;
+
 
 
-  handleCheckBox() {
-    this.setState({ sendEmail: !this.state.sendEmail });
+    try {
+      const res = await apiv3Put('/users/reset-password-email', { id: userForPasswordResetModal._id });
+      const { failedToSendEmail } = res.data;
+      if (failedToSendEmail == null) {
+        const msg = `Email has been sent ${userForPasswordResetModal.email}`;
+        toastSuccess(msg);
+      }
+      else {
+        const msg = { message: `email: ${failedToSendEmail.email}<br>reason: ${failedToSendEmail.reason}` };
+        toastError(msg);
+      }
+    }
+    catch (err) {
+      toastError(err);
+    }
+    finally {
+      this.setState({ isCreateUserButtonPushed: false });
+    }
   }
   }
 
 
+
   render() {
   render() {
     const { t } = this.props;
     const { t } = this.props;
 
 
@@ -146,6 +193,8 @@ PasswordResetModal.propTypes = {
   isOpen: PropTypes.bool.isRequired,
   isOpen: PropTypes.bool.isRequired,
   onClose: PropTypes.func.isRequired,
   onClose: PropTypes.func.isRequired,
   userForPasswordResetModal: PropTypes.object,
   userForPasswordResetModal: PropTypes.object,
+  onSuccessfullySentNewPasswordEmail: PropTypes.func.isRequired,
+  adminUsersContainer: PropTypes.instanceOf(AdminUsersContainer).isRequired,
 
 
 };
 };
 
 

+ 53 - 0
apps/app/src/server/routes/apiv3/users.js

@@ -181,6 +181,37 @@ module.exports = (crowi) => {
     return { failedToSendEmailList };
     return { failedToSendEmailList };
   };
   };
 
 
+
+  const sendEmailByUser = async(user) => {
+    const { appService, mailService } = crowi;
+    const appTitle = appService.getAppTitle();
+    const failedToSendEmailList = [];
+
+    try {
+      // eslint-disable-next-line no-await-in-loop
+      await mailService.send({
+        to: user.email,
+        subject: `New password for ${appTitle}`,
+        template: path.join(crowi.localeDir, 'en_US/admin/userResetPassword.txt'),
+        vars: {
+          email: user.email,
+          password: user.password,
+          url: crowi.appService.getSiteUrl(),
+          appTitle,
+        },
+      });
+    }
+    catch (err) {
+      logger.error(err);
+      failedToSendEmailList.push({
+        email: user.email,
+        reason: err.message,
+      });
+    }
+
+    return { failedToSendEmailList };
+  };
+
   /**
   /**
    * @swagger
    * @swagger
    *
    *
@@ -966,6 +997,28 @@ module.exports = (crowi) => {
     }
     }
   });
   });
 
 
+  router.put('/reset-password-email', loginRequiredStrictly, adminRequired, addActivity, async(req, res) => {
+    const { id } = req.body;
+    const user = await User.findById(id);
+    const newPassword = await User.resetPasswordByRandomString(id);
+
+    try {
+      const userInfo = {
+        email: user.email,
+        password: newPassword,
+        user: { id },
+      };
+
+      const sendEmail = await sendEmailByUser(userInfo);
+
+      return res.apiv3({ newPassword, user, failedToSendEmail: sendEmail.failedToSendEmailList[0] });
+    }
+    catch (err) {
+      logger.error('Error', err);
+      return res.apiv3Err(new ErrorV3(err));
+    }
+  });
+
   /**
   /**
    * @swagger
    * @swagger
    *
    *