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

Merge pull request #1884 from weseek/support/create-apiV3-for-update-bokkmark-status

Support/create api v3 for update bookmark status
Yuki Takei 6 лет назад
Родитель
Сommit
663d1bcbb7

+ 31 - 39
src/client/js/components/BookmarkButton.jsx

@@ -1,58 +1,51 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 
-export default class BookmarkButton extends React.Component {
+import { toastError } from '../util/apiNotification';
+
+class BookmarkButton extends React.Component {
 
   constructor(props) {
     super(props);
 
     this.state = {
-      bookmarked: false,
+      isBookmarked: false,
     };
 
     this.handleClick = this.handleClick.bind(this);
   }
 
-  componentDidMount() {
+  async componentDidMount() {
+    const { pageId, crowi } = this.props;
     // if guest user
     if (!this.isUserLoggedIn()) {
       // do nothing
       return;
     }
 
-    this.props.crowi.apiGet('/bookmarks.get', { page_id: this.props.pageId })
-      .then((res) => {
-        if (res.bookmark) {
-          this.markBookmarked();
-        }
-      });
-  }
-
-  handleClick(event) {
-    event.preventDefault();
-
-    const pageId = this.props.pageId;
-
-    if (!this.state.bookmarked) {
-      this.props.crowi.apiPost('/bookmarks.add', { page_id: pageId })
-        .then((res) => {
-          this.markBookmarked();
-        });
+    try {
+      const response = await crowi.apiv3.get('/bookmarks', { pageId });
+      if (response.data.bookmark != null) {
+        this.setState({ isBookmarked: true });
+      }
     }
-    else {
-      this.props.crowi.apiPost('/bookmarks.remove', { page_id: pageId })
-        .then((res) => {
-          this.markUnBookmarked();
-        });
+    catch (err) {
+      toastError(err);
     }
-  }
 
-  markBookmarked() {
-    this.setState({ bookmarked: true });
   }
 
-  markUnBookmarked() {
-    this.setState({ bookmarked: false });
+  async handleClick() {
+    const { crowi, pageId } = this.props;
+    const bool = !this.state.isBookmarked;
+
+    try {
+      await crowi.apiv3.put('/bookmarks', { pageId, bool });
+      this.setState({ isBookmarked: bool });
+    }
+    catch (err) {
+      toastError(err);
+    }
   }
 
   isUserLoggedIn() {
@@ -65,20 +58,13 @@ export default class BookmarkButton extends React.Component {
       return <div></div>;
     }
 
-    const btnSizeClassName = this.props.size ? `btn-${this.props.size}` : 'btn-md';
-    const addedClassNames = [
-      this.state.bookmarked ? 'active' : '',
-      btnSizeClassName,
-    ];
-    const addedClassName = addedClassNames.join(' ');
-
     return (
       <button
         type="button"
         href="#"
         title="Bookmark"
         onClick={this.handleClick}
-        className={`btn btn-circle btn-outline-warning btn-bookmark border-0 ${addedClassName}`}
+        className={`btn btn-circle btn-outline-warning btn-bookmark border-0 ${`btn-${this.props.size}`} ${this.state.bookmarked && 'active'}`}
       >
         <i className="icon-star"></i>
       </button>
@@ -92,3 +78,9 @@ BookmarkButton.propTypes = {
   crowi: PropTypes.object.isRequired,
   size: PropTypes.string,
 };
+
+BookmarkButton.defaultProps = {
+  size: 'md',
+};
+
+export default BookmarkButton;

+ 1 - 1
src/client/js/components/Navbar/GrowiSubNavigationForUserPage.jsx

@@ -57,7 +57,7 @@ const GrowiSubNavigationForUserPage = (props) => {
         </div>
 
         {/* Header Button */}
-        <BookmarkButton pageId={pageId} crowi={appContainer} />
+        <BookmarkButton pageId={pageId} crowi={appContainer} size="lg" />
       </div>
 
 

+ 157 - 0
src/server/routes/apiv3/bookmarks.js

@@ -0,0 +1,157 @@
+const loggerFactory = require('@alias/logger');
+
+const logger = loggerFactory('growi:routes:apiv3:bookmark'); // eslint-disable-line no-unused-vars
+
+const express = require('express');
+const { body } = require('express-validator');
+
+const router = express.Router();
+
+/**
+ * @swagger
+ *  tags:
+ *    name: Bookmarks
+ */
+
+/**
+ * @swagger
+ *
+ *  components:
+ *    schemas:
+ *      Bookmark:
+ *        description: Bookmark
+ *        type: object
+ *        properties:
+ *          _id:
+ *            type: string
+ *            description: page ID
+ *            example: 5e07345972560e001761fa63
+ *          __v:
+ *            type: number
+ *            description: DB record version
+ *            example: 0
+ *          createdAt:
+ *            type: string
+ *            description: date created at
+ *            example: 2010-01-01T00:00:00.000Z
+ *          page:
+ *            $ref: '#/components/schemas/Page/properties/_id'
+ *          user:
+ *            $ref: '#/components/schemas/User/properties/_id'
+ *
+ *      BookmarkParams:
+ *        description: BookmarkParams
+ *        type: object
+ *        properties:
+ *          pageId:
+ *            type: string
+ *            description: page ID
+ *            example: 5e07345972560e001761fa63
+ *          bool:
+ *            type: boolean
+ *            description: boolean for bookmark status
+ */
+
+module.exports = (crowi) => {
+  const accessTokenParser = require('../../middleware/access-token-parser')(crowi);
+  const loginRequired = require('../../middleware/login-required')(crowi);
+  const csrf = require('../../middleware/csrf')(crowi);
+
+  const { Page, Bookmark } = crowi.models;
+  const { ApiV3FormValidator } = crowi.middlewares;
+
+  const validator = {
+    bookmarks: [
+      body('pageId').isString(),
+      body('bool').isBoolean(),
+    ],
+  };
+
+  /**
+   * @swagger
+   *
+   *    /bookmarks:
+   *      get:
+   *        tags: [Bookmarks]
+   *        summary: /bookmarks
+   *        description: Get bookmarked status
+   *        operationId: getBookmarkedStatus
+   *        parameters:
+   *          - name: pageId
+   *            in: query
+   *            description: page id
+   *            schema:
+   *              type: string
+   *        responses:
+   *          200:
+   *            description: Succeeded to get bookmarked status.
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  $ref: '#/components/schemas/Bookmark'
+   */
+  router.get('/', accessTokenParser, loginRequired, async(req, res) => {
+    const { pageId } = req.query;
+
+    try {
+      const bookmark = await Bookmark.findByPageIdAndUserId(pageId, req.user);
+      return res.apiv3({ bookmark });
+    }
+    catch (err) {
+      logger.error('get-bookmark-failed', err);
+      return res.apiv3Err(err, 500);
+    }
+  });
+
+
+  /**
+   * @swagger
+   *
+   *    /bookmarks:
+   *      put:
+   *        tags: [Bookmarks]
+   *        summary: /bookmarks
+   *        description: Update bookmarked status
+   *        operationId: updateBookmarkedStatus
+   *        requestBody:
+   *          content:
+   *            application/json:
+   *              schema:
+   *                $ref: '#/components/schemas/BookmarkParams'
+   *        responses:
+   *          200:
+   *            description: Succeeded to update bookmarked status.
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  $ref: '#/components/schemas/Bookmark'
+   */
+  router.put('/', accessTokenParser, loginRequired, csrf, validator.bookmarks, ApiV3FormValidator, async(req, res) => {
+    const { pageId, bool } = req.body;
+
+    let bookmark;
+    try {
+      const page = await Page.findByIdAndViewer(pageId, req.user);
+      if (page == null) {
+        return res.apiv3Err(`Page '${pageId}' is not found or forbidden`);
+      }
+      if (bool) {
+        bookmark = await Bookmark.add(page, req.user);
+      }
+      else {
+        bookmark = await Bookmark.removeBookmark(page, req.user);
+      }
+    }
+    catch (err) {
+      logger.error('update-bookmark-failed', err);
+      return res.apiv3Err(err, 500);
+    }
+
+    bookmark.depopulate('page');
+    bookmark.depopulate('user');
+
+    return res.apiv3({ bookmark });
+  });
+
+  return router;
+};

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

@@ -39,5 +39,7 @@ module.exports = (crowi) => {
 
   router.use('/page', require('./page')(crowi));
 
+  router.use('/bookmarks', require('./bookmarks')(crowi));
+
   return router;
 };