revisions.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. const loggerFactory = require('@alias/logger');
  2. const logger = loggerFactory('growi:routes:apiv3:pages');
  3. const express = require('express');
  4. const { query, param } = require('express-validator');
  5. const ErrorV3 = require('../../models/vo/error-apiv3');
  6. const router = express.Router();
  7. /**
  8. * @swagger
  9. * tags:
  10. * name: Revisions
  11. */
  12. /**
  13. * @swagger
  14. *
  15. * components:
  16. * schemas:
  17. * Revision:
  18. * description: Revision
  19. * type: object
  20. * properties:
  21. * _id:
  22. * type: string
  23. * description: revision ID
  24. * example: 5e0734e472560e001761fa68
  25. * __v:
  26. * type: number
  27. * description: DB record version
  28. * example: 0
  29. * author:
  30. * $ref: '#/components/schemas/User/properties/_id'
  31. * body:
  32. * type: string
  33. * description: content body
  34. * example: |
  35. * # test
  36. *
  37. * test
  38. * format:
  39. * type: string
  40. * description: format
  41. * example: markdown
  42. * path:
  43. * type: string
  44. * description: path
  45. * example: /user/alice/test
  46. * createdAt:
  47. * type: string
  48. * description: date created at
  49. * example: 2010-01-01T00:00:00.000Z
  50. */
  51. module.exports = (crowi) => {
  52. const certifySharedPage = require('../../middlewares/certify-shared-page')(crowi);
  53. const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
  54. const loginRequired = require('../../middlewares/login-required')(crowi, true);
  55. const apiV3FormValidator = require('../../middlewares/apiv3-form-validator')(crowi);
  56. const {
  57. Revision,
  58. Page,
  59. User,
  60. } = crowi.models;
  61. const validator = {
  62. retrieveRevisions: [
  63. query('pageId').isMongoId().withMessage('pageId is required'),
  64. query('page').isInt({ min: 0 }).withMessage('page must be int'),
  65. query('limit').if(value => value != null).isInt({ max: 100 }).withMessage('You should set less than 100 or not to set limit.'),
  66. ],
  67. retrieveRevisionById: [
  68. query('pageId').isMongoId().withMessage('pageId is required'),
  69. param('id').isMongoId().withMessage('id is required'),
  70. ],
  71. };
  72. /**
  73. * @swagger
  74. *
  75. * /revisions/list:
  76. * get:
  77. * tags: [Revisions]
  78. * description: Get revisions by page id
  79. * parameters:
  80. * - in: query
  81. * name: pageId
  82. * schema:
  83. * type: string
  84. * description: page id
  85. * responses:
  86. * 200:
  87. * description: Return revisions belong to page
  88. *
  89. */
  90. router.get('/list', certifySharedPage, accessTokenParser, loginRequired, validator.retrieveRevisions, apiV3FormValidator, async(req, res) => {
  91. const pageId = req.query.pageId;
  92. const limit = req.query.limit || await crowi.configManager.getConfig('crowi', 'customize:showPageLimitationS') || 10;
  93. const { isSharedPage } = req;
  94. const selectedPage = parseInt(req.query.page) || 1;
  95. // check whether accessible
  96. if (!isSharedPage && !(await Page.isAccessiblePageByViewer(pageId, req.user))) {
  97. return res.apiv3Err(new ErrorV3('Current user is not accessible to this page.', 'forbidden-page'), 403);
  98. }
  99. try {
  100. const page = await Page.findOne({ _id: pageId });
  101. const paginateResult = await Revision.paginate(
  102. { path: page.path },
  103. {
  104. page: selectedPage,
  105. limit,
  106. sort: { createdAt: -1 },
  107. populate: {
  108. path: 'author',
  109. select: User.USER_PUBLIC_FIELDS,
  110. },
  111. },
  112. );
  113. return res.apiv3(paginateResult);
  114. }
  115. catch (err) {
  116. const msg = 'Error occurred in getting revisions by poge id';
  117. logger.error('Error', err);
  118. return res.apiv3Err(new ErrorV3(msg, 'faild-to-find-revisions'), 500);
  119. }
  120. });
  121. /**
  122. * @swagger
  123. *
  124. * /revisions/{id}:
  125. * get:
  126. * tags: [Revisions]
  127. * description: Get one revision by id
  128. * parameters:
  129. * - in: query
  130. * name: pageId
  131. * required: true
  132. * description: page id
  133. * schema:
  134. * type: string
  135. * - in: path
  136. * name: id
  137. * required: true
  138. * description: revision id
  139. * schema:
  140. * type: string
  141. * responses:
  142. * 200:
  143. * description: Return revision
  144. *
  145. */
  146. router.get('/:id', certifySharedPage, accessTokenParser, loginRequired, validator.retrieveRevisionById, apiV3FormValidator, async(req, res) => {
  147. const revisionId = req.params.id;
  148. const pageId = req.query.pageId;
  149. const { isSharedPage } = req;
  150. // check whether accessible
  151. if (!isSharedPage && !(await Page.isAccessiblePageByViewer(pageId, req.user))) {
  152. return res.apiv3Err(new ErrorV3('Current user is not accessible to this page.', 'forbidden-page'), 403);
  153. }
  154. try {
  155. const revision = await Revision.findById(revisionId).populate('author', User.USER_PUBLIC_FIELDS);
  156. return res.apiv3({ revision });
  157. }
  158. catch (err) {
  159. const msg = 'Error occurred in getting revision data by id';
  160. logger.error('Error', err);
  161. return res.apiv3Err(new ErrorV3(msg, 'faild-to-find-revision'), 500);
  162. }
  163. });
  164. return router;
  165. };