Parcourir la source

Merge pull request #2410 from weseek/feat/delete-all-links

Feat/delete all links
itizawa il y a 5 ans
Parent
commit
51b2d31c08

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

@@ -345,7 +345,8 @@
     "remove_user_success": "Succeeded to removing {{username}}",
     "remove_external_user_success": "Succeeded to remove {{accountId}}",
     "remove_share_link_success": "Succeeded to remove {{shareLinkId}}",
-    "issue_share_link": "Succeeded to issue new share link"
+    "issue_share_link": "Succeeded to issue new share link",
+    "remove_share_link": "Succeeded to remove {{count}} share links"
   },
   "template": {
     "modal_label": {

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

@@ -346,7 +346,8 @@
     "remove_user_success": "{{username}}を削除しました",
     "remove_external_user_success": "{{accountId}}を削除しました",
     "remove_share_link_success": "{{shareLinkId}}を削除しました",
-    "issue_share_link": "共有リンクを作成しました"
+    "issue_share_link": "共有リンクを作成しました",
+    "remove_share_link": "共有リンクを{{count}}件削除しました"
   },
   "template": {
     "modal_label": {

+ 39 - 3
src/client/js/components/OutsideShareLinkModal.jsx

@@ -15,21 +15,57 @@ import PageContainer from '../services/PageContainer';
 import ShareLinkList from './ShareLinkList';
 import ShareLinkForm from './ShareLinkForm';
 
+import { toastSuccess, toastError } from '../util/apiNotification';
+
 class OutsideShareLinkModal extends React.Component {
 
   constructor() {
     super();
     this.state = {
+      shareLinks: [],
       isOpenShareLinkForm: false,
     };
 
     this.toggleShareLinkFormHandler = this.toggleShareLinkFormHandler.bind(this);
+    this.deleteAllLinksButtonHandler = this.deleteAllLinksButtonHandler.bind(this);
+    this.deleteLinkById = this.deleteLinkById.bind(this);
   }
 
   toggleShareLinkFormHandler() {
     this.setState({ isOpenShareLinkForm: !this.state.isOpenShareLinkForm });
   }
 
+  async deleteAllLinksButtonHandler() {
+    const { t, appContainer, pageContainer } = this.props;
+    const { pageId } = pageContainer.state;
+
+    try {
+      const res = await appContainer.apiv3.delete('/share-links/', { relatedPage: pageId });
+      const count = res.data.n;
+      toastSuccess(t('toaster.remove_share_link', { count }));
+    }
+    catch (err) {
+      toastError(err);
+    }
+
+    // TODO GW-2764 retrieve share links
+  }
+
+  async deleteLinkById(shareLinkId) {
+    const { t, appContainer } = this.props;
+
+    try {
+      const res = await appContainer.apiv3Delete(`/share-links/${shareLinkId}`);
+      const { deletedShareLink } = res.data;
+      toastSuccess(t('remove_share_link_success', { shareLinkId: deletedShareLink._id }));
+    }
+    catch (err) {
+      toastError(err);
+    }
+
+    // TODO GW-2764 retrieve share links
+  }
+
   render() {
     return (
       <Modal size="lg" isOpen={this.props.isOpen} toggle={this.props.onClose}>
@@ -39,11 +75,11 @@ class OutsideShareLinkModal extends React.Component {
           <div className="container">
             <div className="form-inline mb-3">
               <h4>Shared Link List</h4>
-              <button className="ml-auto btn btn-danger" type="button">Delete all links</button>
+              <button className="ml-auto btn btn-danger" type="button" onClick={this.deleteAllLinksButtonHandler}>Delete all links</button>
             </div>
 
             <div>
-              <ShareLinkList />
+              <ShareLinkList shareLinks={this.state.shareLinks} />
               <button
                 className="btn btn-outline-secondary d-block mx-auto px-5 mb-3"
                 type="button"
@@ -51,7 +87,7 @@ class OutsideShareLinkModal extends React.Component {
               >
                 {this.state.isOpenShareLinkForm ? 'Close' : 'New'}
               </button>
-              {this.state.isOpenShareLinkForm && <ShareLinkForm onCloseForm={this.toggleShareLinkFormHandler} />}
+              {this.state.isOpenShareLinkForm && <ShareLinkForm onCloseForm={this.toggleShareLinkFormHandler} onClickDeleteButton={this.deleteLinkById} />}
             </div>
           </div>
         </ModalBody>

+ 2 - 3
src/client/js/components/ShareLinkForm.jsx

@@ -105,7 +105,7 @@ class ShareLinkForm extends React.Component {
   }
 
   async handleIssueShareLink() {
-    const { t, pageContainer } = this.props;
+    const { t, appContainer, pageContainer } = this.props;
     const { pageId } = pageContainer.state;
     const { description } = this.state;
 
@@ -119,7 +119,7 @@ class ShareLinkForm extends React.Component {
     }
 
     try {
-      await this.props.appContainer.apiv3.post('/share-links/', { relatedPage: pageId, expiredAt, description });
+      await appContainer.apiv3Post('/share-links/', { relatedPage: pageId, expiredAt, description });
       this.closeForm();
       toastSuccess(t('toaster.issue_share_link'));
     }
@@ -250,7 +250,6 @@ ShareLinkForm.propTypes = {
   appContainer: PropTypes.instanceOf(AppContainer).isRequired,
   pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
 
-  user: PropTypes.object.isRequired,
   onCloseForm: PropTypes.func,
 };
 

+ 10 - 33
src/client/js/components/ShareLinkList.jsx

@@ -3,50 +3,24 @@ import PropTypes from 'prop-types';
 
 
 import { withTranslation } from 'react-i18next';
-import { toastSuccess, toastError } from '../util/apiNotification';
 
 import { withUnstatedContainers } from './UnstatedUtils';
 
 import AppContainer from '../services/AppContainer';
 
 const ShareLinkList = (props) => {
-  const { t, appContainer } = props;
 
-  async function deleteLinkHandler(shareLinkId) {
-    try {
-      const res = await appContainer.apiv3Delete(`/share-links/${shareLinkId}`);
-      const { deletedShareLink } = res.data;
-      toastSuccess(t('remove_share_link_success', { shareLinkId: deletedShareLink._id }));
-    }
-    catch (err) {
-      toastError(err);
+  function deleteLinkHandler(shareLinkId) {
+    if (props.onClickDeleteButton == null) {
+      return;
     }
+    props.onClickDeleteButton(shareLinkId);
   }
 
-  function GetShareLinkList() {
-    // dummy data
-    const dummyDate = new Date().toString();
-    const shareLinks = [
-      {
-        _id: '507f1f77bcf86cd799439011', link: '/507f1f77bcf86cd799439011', expiration: dummyDate, description: 'foobar',
-      },
-      {
-        _id: '52fcebd19a5c4ea066dbfa12', link: '/52fcebd19a5c4ea066dbfa12', expiration: dummyDate, description: 'test',
-      },
-      {
-        _id: '54759eb3c090d83494e2d804', link: '/54759eb3c090d83494e2d804', expiration: dummyDate, description: 'hoge',
-      },
-      {
-        _id: '5349b4ddd2781d08c09890f3', link: '/5349b4ddd2781d08c09890f3', expiration: dummyDate, description: 'fuga',
-      },
-      {
-        _id: '5349b4ddd2781d08c09890f4', link: '/5349b4ddd2781d08c09890f4', expiration: dummyDate, description: 'piyo',
-      },
-    ];
-
+  function renderShareLinks() {
     return (
       <>
-        {shareLinks.map(shareLink => (
+        {props.shareLinks.map(shareLink => (
           <tr>
             <td>{shareLink.link}</td>
             <td>{shareLink.expiration}</td>
@@ -74,7 +48,7 @@ const ShareLinkList = (props) => {
           </tr>
         </thead>
         <tbody>
-          <GetShareLinkList />
+          {renderShareLinks()}
         </tbody>
       </table>
     </div>
@@ -86,6 +60,9 @@ const ShareLinkListWrapper = withUnstatedContainers(ShareLinkList, [AppContainer
 ShareLinkList.propTypes = {
   t: PropTypes.func.isRequired, //  i18next
   appContainer: PropTypes.instanceOf(AppContainer).isRequired,
+
+  shareLinks: PropTypes.array.isRequired,
+  onClickDeleteButton: PropTypes.func,
 };
 
 export default withTranslation()(ShareLinkListWrapper);

+ 8 - 10
src/server/routes/apiv3/share-links.js

@@ -123,21 +123,19 @@ module.exports = (crowi) => {
   *        tags: [ShareLinks]
   *        summary: /share-links/
   *        description: delete all share links related one page
-  *        requestBody:
-  *           required: true
-  *           content:
-  *             application/json:
-  *               schema:
-  *                 properties:
-  *                   relatedPage:
-  *                     type: string
-  *                     description: delete all share links that related one page
+  *        parameters:
+  *          - name: relatedPage
+  *            in: query
+  *            required: true
+  *            description: page id of share link
+  *            schema:
+  *              type: string
   *        responses:
   *          200:
   *            description: Succeeded to delete o all share links related one page
   */
   router.delete('/', loginRequired, csrf, async(req, res) => {
-    const { relatedPage } = req.body;
+    const { relatedPage } = req.query;
     const ShareLink = crowi.model('ShareLink');
 
     try {