Browse Source

Merge pull request #2655 from weseek/imprv/create-apiv3-revisions-get

Imprv/create apiv3 revisions get
Yuki Takei 5 years ago
parent
commit
ff2c0335b5

+ 5 - 7
src/client/js/components/Page/RevisionLoader.jsx

@@ -40,22 +40,20 @@ class RevisionLoader extends React.Component {
       this.setState({ isLoading: true });
       this.setState({ isLoading: true });
     }
     }
 
 
-    const requestData = {
-      page_id: this.props.pageId,
-      revision_id: this.props.revisionId,
-    };
+    const { pageId, revisionId } = this.props;
+
 
 
     // load data with REST API
     // load data with REST API
     try {
     try {
-      const res = await this.props.appContainer.apiGet('/revisions.get', requestData);
+      const res = await this.props.appContainer.apiv3Get(`/revisions/${revisionId}`, { pageId });
 
 
       this.setState({
       this.setState({
-        markdown: res.revision.body,
+        markdown: res.data.revision.body,
         error: null,
         error: null,
       });
       });
 
 
       if (this.props.onRevisionLoaded != null) {
       if (this.props.onRevisionLoaded != null) {
-        this.props.onRevisionLoaded(res.revision);
+        this.props.onRevisionLoaded(res.data.revision);
       }
       }
     }
     }
     catch (error) {
     catch (error) {

+ 1 - 1
src/client/js/components/PageHistory.jsx

@@ -23,7 +23,7 @@ function PageHistory(props) {
       }
       }
       catch (err) {
       catch (err) {
         toastError(err);
         toastError(err);
-        pageHistoryContainer.setState({ retrieveError: err.message });
+        pageHistoryContainer.setState({ errorMessage: err.message });
         logger.error(err);
         logger.error(err);
       }
       }
     });
     });

+ 30 - 21
src/client/js/services/PageHistoryContainer.js

@@ -1,5 +1,11 @@
 import { Container } from 'unstated';
 import { Container } from 'unstated';
 
 
+import loggerFactory from '@alias/logger';
+
+import { toastError } from '../util/apiNotification';
+
+const logger = loggerFactory('growi:PageHistoryContainer');
+
 /**
 /**
  * Service container for personal settings page (PageHistory.jsx)
  * Service container for personal settings page (PageHistory.jsx)
  * @extends {Container} unstated Container
  * @extends {Container} unstated Container
@@ -15,7 +21,7 @@ export default class PageHistoryContainer extends Container {
     this.dummyRevisions = 0;
     this.dummyRevisions = 0;
 
 
     this.state = {
     this.state = {
-      retrieveError: null,
+      errorMessage: null,
 
 
       // set dummy rivisions for using suspense
       // set dummy rivisions for using suspense
       revisions: this.dummyRevisions,
       revisions: this.dummyRevisions,
@@ -105,33 +111,36 @@ export default class PageHistoryContainer extends Container {
     return cursor;
     return cursor;
   }
   }
 
 
-  fetchPageRevisionBody(revision) {
+  /**
+   * fetch page revision body by revision in argument
+   * @param {object} revision
+   */
+  async fetchPageRevisionBody(revision) {
     const { pageId, shareLinkId } = this.pageContainer.state;
     const { pageId, shareLinkId } = this.pageContainer.state;
 
 
     if (revision.body) {
     if (revision.body) {
       return;
       return;
     }
     }
 
 
-    // TODO GW-3487 apiV3
-    this.appContainer.apiGet('/revisions.get', { page_id: pageId, revision_id: revision._id, share_link_id: shareLinkId })
-      .then((res) => {
-        if (res.ok) {
-          this.setState({
-            revisions: this.state.revisions.map((rev) => {
-              // comparing ObjectId
-              // eslint-disable-next-line eqeqeq
-              if (rev._id == res.revision._id) {
-                return res.revision;
-              }
-
-              return rev;
-            }),
-          });
-        }
-      })
-      .catch((err) => {
-
+    try {
+      const res = await this.appContainer.apiv3Get(`/revisions/${revision._id}`, { pageId, share_link_id: shareLinkId });
+      this.setState({
+        revisions: this.state.revisions.map((rev) => {
+          // comparing ObjectId
+          // eslint-disable-next-line eqeqeq
+          if (rev._id == res.data.revision._id) {
+            return res.data.revision;
+          }
+
+          return rev;
+        }),
       });
       });
+    }
+    catch (err) {
+      toastError(err);
+      this.setState({ errorMessage: err.message });
+      logger.error(err);
+    }
   }
   }
 
 
 
 

+ 54 - 2
src/server/routes/apiv3/revisions.js

@@ -4,7 +4,7 @@ const logger = loggerFactory('growi:routes:apiv3:pages');
 
 
 const express = require('express');
 const express = require('express');
 
 
-const { query } = require('express-validator/check');
+const { query, param } = require('express-validator/check');
 const ErrorV3 = require('../../models/vo/error-apiv3');
 const ErrorV3 = require('../../models/vo/error-apiv3');
 
 
 const router = express.Router();
 const router = express.Router();
@@ -23,11 +23,16 @@ module.exports = (crowi) => {
   const {
   const {
     Revision,
     Revision,
     Page,
     Page,
+    User,
   } = crowi.models;
   } = crowi.models;
 
 
   const validator = {
   const validator = {
     retrieveRevisions: [
     retrieveRevisions: [
-      query('pageId').exists().withMessage('pageId is required'),
+      query('pageId').isMongoId().withMessage('pageId is required'),
+    ],
+    retrieveRevisionById: [
+      query('pageId').isMongoId().withMessage('pageId is required'),
+      param('id').isMongoId().withMessage('id is required'),
     ],
     ],
   };
   };
 
 
@@ -71,5 +76,52 @@ module.exports = (crowi) => {
 
 
   });
   });
 
 
+  /**
+   * @swagger
+   *
+   *    /revisions/{id}:
+   *      get:
+   *        tags: [Revisions]
+   *        description: Get one revision by id
+   *        parameters:
+   *          - in: query
+   *            name: pageId
+   *            required: true
+   *            description: page id
+   *            schema:
+   *              type: string
+   *          - in: path
+   *            name: id
+   *            required: true
+   *            description: revision id
+   *            schema:
+   *              type: string
+   *        responses:
+   *          200:
+   *            description: Return revision
+   *
+   */
+  router.get('/:id', certifySharedPage, accessTokenParser, loginRequired, validator.retrieveRevisionById, apiV3FormValidator, async(req, res) => {
+    const revisionId = req.params.id;
+    const { pageId } = req.query;
+    const { isSharedPage } = req;
+
+    // check whether accessible
+    if (!isSharedPage && !(await Page.isAccessiblePageByViewer(pageId, req.user))) {
+      return res.apiv3Err(new ErrorV3('Current user is not accessible to this page.', 'forbidden-page'), 403);
+    }
+
+    try {
+      const revision = await Revision.findById(revisionId).populate('author', User.USER_PUBLIC_FIELDS);
+      return res.apiv3({ revision });
+    }
+    catch (err) {
+      const msg = 'Error occurred in getting revision data by id';
+      logger.error('Error', err);
+      return res.apiv3Err(new ErrorV3(msg, 'faild-to-find-revision'), 500);
+    }
+
+  });
+
   return router;
   return router;
 };
 };

+ 0 - 5
src/server/routes/index.js

@@ -10,7 +10,6 @@ module.exports = function(crowi, app) {
   const loginRequiredStrictly = require('../middlewares/login-required')(crowi);
   const loginRequiredStrictly = require('../middlewares/login-required')(crowi);
   const loginRequired = require('../middlewares/login-required')(crowi, true);
   const loginRequired = require('../middlewares/login-required')(crowi, true);
   const adminRequired = require('../middlewares/admin-required')(crowi);
   const adminRequired = require('../middlewares/admin-required')(crowi);
-  const certifySharedPage = require('../middlewares/certify-shared-page')(crowi);
   const certifySharedFile = require('../middlewares/certify-shared-file')(crowi);
   const certifySharedFile = require('../middlewares/certify-shared-file')(crowi);
   const csrf = require('../middlewares/csrf')(crowi);
   const csrf = require('../middlewares/csrf')(crowi);
 
 
@@ -26,7 +25,6 @@ module.exports = function(crowi, app) {
   const attachment = require('./attachment')(crowi, app);
   const attachment = require('./attachment')(crowi, app);
   const comment = require('./comment')(crowi, app);
   const comment = require('./comment')(crowi, app);
   const tag = require('./tag')(crowi, app);
   const tag = require('./tag')(crowi, app);
-  const revision = require('./revision')(crowi, app);
   const search = require('./search')(crowi, app);
   const search = require('./search')(crowi, app);
   const hackmd = require('./hackmd')(crowi, app);
   const hackmd = require('./hackmd')(crowi, app);
 
 
@@ -166,9 +164,6 @@ module.exports = function(crowi, app) {
   app.post('/_api/attachments.removeProfileImage'   , accessTokenParser , loginRequiredStrictly , csrf, attachment.api.removeProfileImage);
   app.post('/_api/attachments.removeProfileImage'   , accessTokenParser , loginRequiredStrictly , csrf, attachment.api.removeProfileImage);
   app.get('/_api/attachments.limit'   , accessTokenParser , loginRequiredStrictly, attachment.api.limit);
   app.get('/_api/attachments.limit'   , accessTokenParser , loginRequiredStrictly, attachment.api.limit);
 
 
-  app.get('/_api/revisions.get'       , certifySharedPage , accessTokenParser , loginRequired , revision.api.get);
-  app.get('/_api/revisions.ids'       , certifySharedPage , accessTokenParser , loginRequired , revision.api.ids);
-
   app.get('/trash$'                   , loginRequired , page.trashPageShowWrapper);
   app.get('/trash$'                   , loginRequired , page.trashPageShowWrapper);
   app.get('/trash/$'                  , loginRequired , page.trashPageListShowWrapper);
   app.get('/trash/$'                  , loginRequired , page.trashPageListShowWrapper);
   app.get('/trash/*/$'                , loginRequired , page.deletedPageListShowWrapper);
   app.get('/trash/*/$'                , loginRequired , page.deletedPageListShowWrapper);

+ 0 - 190
src/server/routes/revision.js

@@ -1,190 +0,0 @@
-/**
- * @swagger
- *  tags:
- *    name: Revisions
- */
-
-/**
- * @swagger
- *
- *  components:
- *    schemas:
- *      Revision:
- *        description: Revision
- *        type: object
- *        properties:
- *          _id:
- *            type: string
- *            description: revision ID
- *            example: 5e0734e472560e001761fa68
- *          __v:
- *            type: number
- *            description: DB record version
- *            example: 0
- *          author:
- *            $ref: '#/components/schemas/User/properties/_id'
- *          body:
- *            type: string
- *            description: content body
- *            example: |
- *              # test
- *
- *              test
- *          format:
- *            type: string
- *            description: format
- *            example: markdown
- *          path:
- *            type: string
- *            description: path
- *            example: /user/alice/test
- *          createdAt:
- *            type: string
- *            description: date created at
- *            example: 2010-01-01T00:00:00.000Z
- */
-
-module.exports = function(crowi, app) {
-  const logger = require('@alias/logger')('growi:routes:revision');
-  const Page = crowi.model('Page');
-  const Revision = crowi.model('Revision');
-  const User = crowi.model('User');
-  const ApiResponse = require('../util/apiResponse');
-
-  const actions = {};
-  actions.api = {};
-
-  /**
-   * @swagger
-   *
-   *    /revisions.get:
-   *      get:
-   *        tags: [Revisions, CrowiCompatibles]
-   *        operationId: revisions.get
-   *        summary: /revisions.get
-   *        description: Get revision
-   *        parameters:
-   *          - in: query
-   *            name: page_id
-   *            schema:
-   *              $ref: '#/components/schemas/Page/properties/_id'
-   *            required: true
-   *          - in: query
-   *            name: revision_id
-   *            schema:
-   *              $ref: '#/components/schemas/Revision/properties/_id'
-   *            required: true
-   *        responses:
-   *          200:
-   *            description: Succeeded to get revision.
-   *            content:
-   *              application/json:
-   *                schema:
-   *                  properties:
-   *                    ok:
-   *                      $ref: '#/components/schemas/V1Response/properties/ok'
-   *                    revision:
-   *                      $ref: '#/components/schemas/Revision'
-   *          403:
-   *            $ref: '#/components/responses/403'
-   *          500:
-   *            $ref: '#/components/responses/500'
-   */
-  /**
-   * @api {get} /revisions.get Get revision
-   * @apiName GetRevision
-   * @apiGroup Revision
-   *
-   * @apiParam {String} page_id Page Id.
-   * @apiParam {String} revision_id Revision Id.
-   */
-  actions.api.get = async function(req, res) {
-    const pageId = req.query.page_id;
-    const revisionId = req.query.revision_id;
-    const { isSharedPage } = req;
-
-    if (!pageId || !revisionId) {
-      return res.json(ApiResponse.error('Parameter page_id and revision_id are required.'));
-    }
-
-    // check whether accessible
-    if (!isSharedPage && !(await Page.isAccessiblePageByViewer(pageId, req.user))) {
-      return res.json(ApiResponse.error('Current user is not accessible to this page.'));
-    }
-
-    try {
-      const revision = await Revision.findById(revisionId).populate('author', User.USER_PUBLIC_FIELDS);
-      return res.json(ApiResponse.success({ revision }));
-    }
-    catch (err) {
-      logger.error('Error revisios.get', err);
-      return res.json(ApiResponse.error(err));
-    }
-  };
-
-  /**
-   * @swagger
-   *
-   *    /revisions.ids:
-   *      get:
-   *        tags: [Revisions, CrowiCompatibles]
-   *        operationId: revisions.ids
-   *        summary: /revisions.ids
-   *        description: Get revision id list of the page
-   *        parameters:
-   *          - in: query
-   *            name: page_id
-   *            schema:
-   *              $ref: '#/components/schemas/Page/properties/_id'
-   *            required: true
-   *        responses:
-   *          200:
-   *            description: Succeeded to get revision id list of the page.
-   *            content:
-   *              application/json:
-   *                schema:
-   *                  properties:
-   *                    ok:
-   *                      $ref: '#/components/schemas/V1Response/properties/ok'
-   *                    revisions:
-   *                      type: array
-   *                      items:
-   *                        $ref: '#/components/schemas/Revision'
-   *          403:
-   *            $ref: '#/components/responses/403'
-   *          500:
-   *            $ref: '#/components/responses/500'
-   */
-  /**
-   * @api {get} /revisions.ids Get revision id list of the page
-   * @apiName ids
-   * @apiGroup Revision
-   *
-   * @apiParam {String} page_id      Page Id.
-   */
-  actions.api.ids = async function(req, res) {
-    const pageId = req.query.page_id;
-    const { isSharedPage } = req;
-
-    if (pageId == null) {
-      return res.json(ApiResponse.error('Parameter page_id is required.'));
-    }
-
-    // check whether accessible
-    if (!isSharedPage && !(await Page.isAccessiblePageByViewer(pageId, req.user))) {
-      return res.json(ApiResponse.error('Current user is not accessible to this page.'));
-    }
-
-    try {
-      const page = await Page.findOne({ _id: pageId });
-      const revisions = await Revision.findRevisionIdList(page.path);
-      return res.json(ApiResponse.success({ revisions }));
-    }
-    catch (err) {
-      logger.error('Error revisios.ids', err);
-      return res.json(ApiResponse.error(err));
-    }
-  };
-
-  return actions;
-};