itizawa 5 лет назад
Родитель
Сommit
7d1eda4c48

+ 22 - 6
src/client/js/components/Admin/Security/DeleteAllShareLinksModal.jsx

@@ -9,7 +9,8 @@ import {
 
 const DeleteAllShareLinksModal = React.memo((props) => {
 
-  function closeButtonHandler() {
+
+  function closeModal() {
     if (props.onClose == null) {
       return;
     }
@@ -17,6 +18,20 @@ const DeleteAllShareLinksModal = React.memo((props) => {
     props.onClose();
   }
 
+  function deleteAllLinkHandler() {
+    if (props.onClickDeleteButton == null) {
+      return;
+    }
+
+    props.onClickDeleteButton();
+
+    closeModal();
+  }
+
+  function closeButtonHandler() {
+    closeModal();
+  }
+
   return (
     <Modal isOpen={props.isOpen} toggle={closeButtonHandler} className="page-comment-delete-modal">
       <ModalHeader tag="h4" toggle={closeButtonHandler} className="bg-danger text-light">
@@ -26,14 +41,14 @@ const DeleteAllShareLinksModal = React.memo((props) => {
         </span>
       </ModalHeader>
       <ModalBody>
-        x 件の ShareLink 削除します
+        {props.count} 件の ShareLink 削除します
       </ModalBody>
       <ModalFooter>
         <Button onClick={closeButtonHandler}>Cancel</Button>
-        {/* <Button color="danger" onClick={this.props.confirmedToDelete}>
+        <Button color="danger" onClick={deleteAllLinkHandler}>
           <i className="icon icon-fire"></i>
             Delete
-        </Button> */}
+        </Button>
       </ModalFooter>
     </Modal>
   );
@@ -42,8 +57,9 @@ const DeleteAllShareLinksModal = React.memo((props) => {
 
 DeleteAllShareLinksModal.propTypes = {
   isOpen: PropTypes.bool.isRequired,
-  onClose: PropTypes.func.isRequired,
-
+  onClose: PropTypes.func,
+  count: PropTypes.number.isRequired,
+  onClickDeleteButton: PropTypes.func,
 };
 
 export default withTranslation()(DeleteAllShareLinksModal);

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

@@ -3,8 +3,11 @@ import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
 import { withUnstatedContainers } from '../../UnstatedUtils';
+import { toastSuccess, toastError } from '../../../util/apiNotification';
 
+import AppContainer from '../../../services/AppContainer';
 import AdminGeneralSecurityContainer from '../../../services/AdminGeneralSecurityContainer';
+
 import ShareLinkList from '../../ShareLinkList';
 import DeleteAllShareLinksModal from './DeleteAllShareLinksModal';
 
@@ -20,6 +23,7 @@ class ShareLinkSetting extends React.Component {
 
     this.showDeleteConfirmModal = this.showDeleteConfirmModal.bind(this);
     this.closeDeleteConfirmModal = this.closeDeleteConfirmModal.bind(this);
+    this.deleteAllLinksButtonHandler = this.deleteAllLinksButtonHandler.bind(this);
   }
 
   showDeleteConfirmModal() {
@@ -30,11 +34,28 @@ class ShareLinkSetting extends React.Component {
     this.setState({ isDeleteConfirmModalShown: false });
   }
 
+  async deleteAllLinksButtonHandler() {
+    const { t, appContainer } = this.props;
+
+    try {
+      const res = await appContainer.apiv3Delete('/share-links/all');
+      console.log(res);
+      const count = res.data.n;
+      toastSuccess(t('toaster.remove_share_link', { count }));
+    }
+    catch (err) {
+      toastError(err);
+    }
+
+  }
+
+
   render() {
     return (
       <>
         <h2 className="border-bottom mb-3">
           Shared Link List
+
           <button type="button" className="btn btn-danger pull-right" onClick={this.showDeleteConfirmModal}>Delete all links</button>
         </h2>
 
@@ -46,6 +67,8 @@ class ShareLinkSetting extends React.Component {
         <DeleteAllShareLinksModal
           isOpen={this.state.isDeleteConfirmModalShown}
           onClose={this.closeDeleteConfirmModal}
+          count={this.state.shareLinks.length}
+          onClickDeleteButton={this.deleteAllLinksButtonHandler}
         />
 
       </>
@@ -54,10 +77,13 @@ class ShareLinkSetting extends React.Component {
 
 }
 
-const ShareLinkSettingWrapper = withUnstatedContainers(ShareLinkSetting, [AdminGeneralSecurityContainer]);
+const ShareLinkSettingWrapper = withUnstatedContainers(ShareLinkSetting, [AppContainer, AdminGeneralSecurityContainer]);
 
 ShareLinkSetting.propTypes = {
+  t: PropTypes.func.isRequired, // i18next
+
   adminGeneralSecurityContainer: PropTypes.instanceOf(AdminGeneralSecurityContainer).isRequired,
+  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
 };
 
 export default withTranslation()(ShareLinkSettingWrapper);

+ 26 - 1
src/server/routes/apiv3/share-links.js

@@ -24,6 +24,7 @@ const today = new Date();
 
 module.exports = (crowi) => {
   const loginRequired = require('../../middlewares/login-required')(crowi);
+  const adminRequired = require('../../middlewares/admin-required')(crowi);
   const csrf = require('../../middlewares/csrf')(crowi);
   const apiV3FormValidator = require('../../middlewares/apiv3-form-validator')(crowi);
   const ShareLink = crowi.model('ShareLink');
@@ -136,7 +137,6 @@ module.exports = (crowi) => {
   */
   router.delete('/', loginRequired, csrf, async(req, res) => {
     const { relatedPage } = req.query;
-    const ShareLink = crowi.model('ShareLink');
 
     try {
       const deletedShareLink = await ShareLink.remove({ relatedPage });
@@ -182,6 +182,31 @@ module.exports = (crowi) => {
 
   });
 
+  /**
+  * @swagger
+  *
+  *    /share-links/all:
+  *      delete:
+  *        tags: [ShareLinks]
+  *        description: delete all share links
+  *        responses:
+  *          200:
+  *            description: Succeeded to remove all share links
+  */
+  router.delete('/all', loginRequired, adminRequired, csrf, async(req, res) => {
+
+    try {
+      const deletedShareLink = null;
+      // const deletedShareLink = await ShareLink.deleteMany({});
+      return res.apiv3({ deletedShareLink });
+    }
+    catch (err) {
+      const msg = 'Error occurred in delete all share link';
+      logger.error('Error', err);
+      return res.apiv3Err(new ErrorV3(msg, 'delete-all-shareLink-failed'));
+    }
+  });
+
 
   return router;
 };