search.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import { ErrorV3 } from '@growi/core/dist/models';
  2. import { SupportedAction } from '~/interfaces/activity';
  3. import { accessTokenParser } from '~/server/middlewares/access-token-parser';
  4. import loggerFactory from '~/utils/logger';
  5. import { generateAddActivityMiddleware } from '../../middlewares/add-activity';
  6. import { apiV3FormValidator } from '../../middlewares/apiv3-form-validator';
  7. const logger = loggerFactory('growi:routes:apiv3:search'); // eslint-disable-line no-unused-vars
  8. const express = require('express');
  9. const { body } = require('express-validator');
  10. const router = express.Router();
  11. const noCache = require('nocache');
  12. module.exports = (crowi) => {
  13. const loginRequired = require('../../middlewares/login-required')(crowi);
  14. const adminRequired = require('../../middlewares/admin-required')(crowi);
  15. const addActivity = generateAddActivityMiddleware(crowi);
  16. const activityEvent = crowi.event('activity');
  17. /**
  18. * @swagger
  19. *
  20. * /search/indices:
  21. * get:
  22. * tags: [FullTextSearch Management]
  23. * summary: /search/indices
  24. * description: Get current status of indices
  25. * responses:
  26. * 200:
  27. * description: Status of indices
  28. * content:
  29. * application/json:
  30. * schema:
  31. * properties:
  32. * info:
  33. * type: object
  34. */
  35. router.get('/indices', noCache(), accessTokenParser, loginRequired, adminRequired, async(req, res) => {
  36. const { searchService } = crowi;
  37. if (!searchService.isConfigured) {
  38. return res.apiv3Err(new ErrorV3('SearchService is not configured', 'search-service-unconfigured'), 503);
  39. }
  40. try {
  41. const info = await searchService.getInfoForAdmin();
  42. return res.status(200).send({ info });
  43. }
  44. catch (err) {
  45. return res.apiv3Err(err, 503);
  46. }
  47. });
  48. /**
  49. * @swagger
  50. *
  51. * /search/connection:
  52. * get:
  53. * tags: [FullTextSearch Management]
  54. * summary: /search/connection
  55. * description: Reconnect to Elasticsearch
  56. * responses:
  57. * 200:
  58. * description: Successfully connected
  59. */
  60. router.post('/connection', accessTokenParser, loginRequired, adminRequired, addActivity, async(req, res) => {
  61. const { searchService } = crowi;
  62. if (!searchService.isConfigured) {
  63. return res.apiv3Err(new ErrorV3('SearchService is not configured', 'search-service-unconfigured'));
  64. }
  65. try {
  66. await searchService.reconnectClient();
  67. activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_ADMIN_SEARCH_CONNECTION });
  68. return res.status(200).send();
  69. }
  70. catch (err) {
  71. return res.apiv3Err(err, 503);
  72. }
  73. });
  74. const validatorForPutIndices = [
  75. body('operation').isString().isIn(['rebuild', 'normalize']),
  76. ];
  77. /**
  78. * @swagger
  79. *
  80. * /search/indices:
  81. * put:
  82. * tags: [FullTextSearch Management]
  83. * summary: /search/indices
  84. * description: Operate indices
  85. * requestBody:
  86. * required: true
  87. * content:
  88. * application/json:
  89. * schema:
  90. * properties:
  91. * operation:
  92. * type: string
  93. * description: Operation type against to indices >
  94. * * `normalize` - Normalize indices
  95. * * `rebuild` - Rebuild indices
  96. * enum: [normalize, rebuild]
  97. * responses:
  98. * 200:
  99. * description: Return 200
  100. */
  101. router.put('/indices', accessTokenParser, loginRequired, adminRequired, addActivity, validatorForPutIndices, apiV3FormValidator, async(req, res) => {
  102. const operation = req.body.operation;
  103. const { searchService } = crowi;
  104. if (!searchService.isConfigured) {
  105. return res.apiv3Err(new ErrorV3('SearchService is not configured', 'search-service-unconfigured'));
  106. }
  107. if (!searchService.isReachable) {
  108. return res.apiv3Err(new ErrorV3('SearchService is not reachable', 'search-service-unreachable'));
  109. }
  110. try {
  111. switch (operation) {
  112. case 'normalize':
  113. // wait the processing is terminated
  114. await searchService.normalizeIndices();
  115. activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_ADMIN_SEARCH_INDICES_NORMALIZE });
  116. return res.status(200).send({ message: 'Operation is successfully processed.' });
  117. case 'rebuild':
  118. // NOT wait the processing is terminated
  119. searchService.rebuildIndex();
  120. activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_ADMIN_SEARCH_INDICES_REBUILD });
  121. return res.status(200).send({ message: 'Operation is successfully requested.' });
  122. default:
  123. throw new Error(`Unimplemented operation: ${operation}`);
  124. }
  125. }
  126. catch (err) {
  127. return res.apiv3Err(err, 503);
  128. }
  129. });
  130. return router;
  131. };