bookmarks.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. const loggerFactory = require('@alias/logger');
  2. const logger = loggerFactory('growi:routes:apiv3:bookmarks'); // eslint-disable-line no-unused-vars
  3. const express = require('express');
  4. const { body, query, param } = require('express-validator');
  5. const { serializeUserSecurely } = require('../../models/serializers/user-serializer');
  6. const router = express.Router();
  7. /**
  8. * @swagger
  9. * tags:
  10. * name: Bookmarks
  11. */
  12. /**
  13. * @swagger
  14. *
  15. * components:
  16. * schemas:
  17. * Bookmark:
  18. * description: Bookmark
  19. * type: object
  20. * properties:
  21. * _id:
  22. * type: string
  23. * description: page ID
  24. * example: 5e07345972560e001761fa63
  25. * __v:
  26. * type: number
  27. * description: DB record version
  28. * example: 0
  29. * createdAt:
  30. * type: string
  31. * description: date created at
  32. * example: 2010-01-01T00:00:00.000Z
  33. * page:
  34. * $ref: '#/components/schemas/Page/properties/_id'
  35. * user:
  36. * $ref: '#/components/schemas/User/properties/_id'
  37. *
  38. * BookmarkParams:
  39. * description: BookmarkParams
  40. * type: object
  41. * properties:
  42. * pageId:
  43. * type: string
  44. * description: page ID
  45. * example: 5e07345972560e001761fa63
  46. * bool:
  47. * type: boolean
  48. * description: boolean for bookmark status
  49. *
  50. * BookmarkInfo:
  51. * description: BookmarkInfo
  52. * type: object
  53. * properties:
  54. * sumOfBookmarks:
  55. * type: number
  56. * description: how many people bookmarked the page
  57. * isBookmarked:
  58. * type: boolean
  59. * description: Whether the request user bookmarked (will be returned if the user is included in the request)
  60. */
  61. module.exports = (crowi) => {
  62. const accessTokenParser = require('../../middlewares/access-token-parser')(crowi);
  63. const loginRequiredStrictly = require('@server/middlewares/login-required')(crowi);
  64. const loginRequired = require('../../middlewares/login-required')(crowi, true);
  65. const csrf = require('../../middlewares/csrf')(crowi);
  66. const apiV3FormValidator = require('../../middlewares/apiv3-form-validator')(crowi);
  67. const { Page, Bookmark, User } = crowi.models;
  68. const validator = {
  69. bookmarks: [
  70. body('pageId').isString(),
  71. body('bool').isBoolean(),
  72. ],
  73. bookmarkInfo: [
  74. query('pageId').isMongoId(),
  75. ],
  76. };
  77. /**
  78. * @swagger
  79. *
  80. * /bookmarks/info:
  81. * get:
  82. * tags: [Bookmarks]
  83. * summary: /bookmarks/info
  84. * description: Get bookmarked info
  85. * operationId: getBookmarkedInfo
  86. * parameters:
  87. * - name: pageId
  88. * in: query
  89. * description: page id
  90. * schema:
  91. * type: string
  92. * responses:
  93. * 200:
  94. * description: Succeeded to get bookmark info.
  95. * content:
  96. * application/json:
  97. * schema:
  98. * $ref: '#/components/schemas/BookmarkInfo'
  99. */
  100. router.get('/info', accessTokenParser, loginRequired, validator.bookmarkInfo, apiV3FormValidator, async(req, res) => {
  101. const { user } = req;
  102. const { pageId } = req.query;
  103. const responsesParams = {};
  104. try {
  105. responsesParams.sumOfBookmarks = await Bookmark.countByPageId(pageId);
  106. }
  107. catch (err) {
  108. logger.error('get-bookmark-count-failed', err);
  109. return res.apiv3Err(err, 500);
  110. }
  111. // guest user only get bookmark count
  112. if (user == null) {
  113. return res.apiv3(responsesParams);
  114. }
  115. try {
  116. const bookmark = await Bookmark.findByPageIdAndUserId(pageId, user._id);
  117. responsesParams.isBookmarked = (bookmark != null);
  118. return res.apiv3(responsesParams);
  119. }
  120. catch (err) {
  121. logger.error('get-bookmark-state-failed', err);
  122. return res.apiv3Err(err, 500);
  123. }
  124. });
  125. // select page from bookmark where userid = userid
  126. /**
  127. * @swagger
  128. *
  129. * /bookmarks/{userId}:
  130. * get:
  131. * tags: [Bookmarks]
  132. * summary: /bookmarks/{userId}
  133. * description: Get my bookmarked status
  134. * operationId: getMyBookmarkedStatus
  135. * parameters:
  136. * - name: userId
  137. * in: path
  138. * required: true
  139. * description: user id
  140. * schema:
  141. * type: string
  142. * - name: page
  143. * in: query
  144. * description: selected page number
  145. * schema:
  146. * type: number
  147. * - name: limit
  148. * in: query
  149. * description: page item limit
  150. * schema:
  151. * type: number
  152. * - name: offset
  153. * in: query
  154. * description: page item offset
  155. * schema:
  156. * type: number
  157. * responses:
  158. * 200:
  159. * description: Succeeded to get my bookmarked status.
  160. * content:
  161. * application/json:
  162. * schema:
  163. * $ref: '#/components/schemas/Bookmark'
  164. */
  165. validator.userBookmarkList = [
  166. param('userId').isMongoId().withMessage('userId is required'),
  167. query('page').isInt({ min: 1 }),
  168. query('limit').if(value => value != null).isInt({ max: 300 }).withMessage('You should set less than 300 or not to set limit.'),
  169. ];
  170. router.get('/:userId', accessTokenParser, loginRequired, validator.userBookmarkList, apiV3FormValidator, async(req, res) => {
  171. const { userId } = req.params;
  172. const page = req.query.page;
  173. const limit = parseInt(req.query.limit) || await crowi.configManager.getConfig('crowi', 'customize:showPageLimitationM') || 30;
  174. if (userId == null) {
  175. return res.apiv3Err('User id is not found or forbidden', 400);
  176. }
  177. if (limit == null) {
  178. return res.apiv3Err('Could not catch page limit', 400);
  179. }
  180. try {
  181. const paginationResult = await Bookmark.paginate(
  182. {
  183. user: { $in: userId },
  184. },
  185. {
  186. populate: {
  187. path: 'page',
  188. model: 'Page',
  189. populate: {
  190. path: 'lastUpdateUser',
  191. model: 'User',
  192. },
  193. },
  194. page,
  195. limit,
  196. },
  197. );
  198. paginationResult.docs.forEach((doc) => {
  199. if (doc.page.lastUpdateUser != null && doc.page.lastUpdateUser instanceof User) {
  200. doc.page.lastUpdateUser = serializeUserSecurely(doc.page.lastUpdateUser);
  201. }
  202. });
  203. return res.apiv3({ paginationResult });
  204. }
  205. catch (err) {
  206. logger.error('get-bookmark-failed', err);
  207. return res.apiv3Err(err, 500);
  208. }
  209. });
  210. /**
  211. * @swagger
  212. *
  213. * /bookmarks:
  214. * put:
  215. * tags: [Bookmarks]
  216. * summary: /bookmarks
  217. * description: Update bookmarked status
  218. * operationId: updateBookmarkedStatus
  219. * requestBody:
  220. * content:
  221. * application/json:
  222. * schema:
  223. * $ref: '#/components/schemas/BookmarkParams'
  224. * responses:
  225. * 200:
  226. * description: Succeeded to update bookmarked status.
  227. * content:
  228. * application/json:
  229. * schema:
  230. * $ref: '#/components/schemas/Bookmark'
  231. */
  232. router.put('/', accessTokenParser, loginRequiredStrictly, csrf, validator.bookmarks, apiV3FormValidator, async(req, res) => {
  233. const { pageId, bool } = req.body;
  234. let bookmark;
  235. try {
  236. const page = await Page.findByIdAndViewer(pageId, req.user);
  237. if (page == null) {
  238. return res.apiv3Err(`Page '${pageId}' is not found or forbidden`);
  239. }
  240. if (bool) {
  241. bookmark = await Bookmark.add(page, req.user);
  242. }
  243. else {
  244. bookmark = await Bookmark.removeBookmark(page, req.user);
  245. }
  246. }
  247. catch (err) {
  248. logger.error('update-bookmark-failed', err);
  249. return res.apiv3Err(err, 500);
  250. }
  251. bookmark.depopulate('page');
  252. bookmark.depopulate('user');
  253. return res.apiv3({ bookmark });
  254. });
  255. return router;
  256. };