search.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. module.exports = function(crowi, app) {
  2. // var debug = require('debug')('growi:routes:search')
  3. const Page = crowi.model('Page');
  4. const ApiResponse = require('../util/apiResponse');
  5. const ApiPaginate = require('../util/apiPaginate');
  6. const actions = {};
  7. const api = {};
  8. actions.searchPage = function(req, res) {
  9. const keyword = req.query.q || null;
  10. const search = crowi.getSearcher();
  11. if (!search) {
  12. return res.json(ApiResponse.error('Configuration of ELASTICSEARCH_URI is required.'));
  13. }
  14. return res.render('search', {
  15. q: keyword,
  16. });
  17. };
  18. /**
  19. * @api {get} /search search page
  20. * @apiName Search
  21. * @apiGroup Search
  22. *
  23. * @apiParam {String} q keyword
  24. * @apiParam {String} path
  25. * @apiParam {String} offset
  26. * @apiParam {String} limit
  27. */
  28. api.search = async function(req, res) {
  29. const user = req.user;
  30. const { q: keyword = null, type = null } = req.query;
  31. let paginateOpts;
  32. try {
  33. paginateOpts = ApiPaginate.parseOptionsForElasticSearch(req.query);
  34. }
  35. catch (e) {
  36. res.json(ApiResponse.error(e));
  37. }
  38. if (keyword === null || keyword === '') {
  39. return res.json(ApiResponse.error('keyword should not empty.'));
  40. }
  41. const search = crowi.getSearcher();
  42. if (!search) {
  43. return res.json(ApiResponse.error('Configuration of ELASTICSEARCH_URI is required.'));
  44. }
  45. let userGroups = [];
  46. if (user != null) {
  47. const UserGroupRelation = crowi.model('UserGroupRelation');
  48. userGroups = await UserGroupRelation.findAllUserGroupIdsRelatedToUser(user);
  49. }
  50. const searchOpts = { ...paginateOpts, type };
  51. const result = {};
  52. try {
  53. const esResult = await search.searchKeyword(keyword, user, userGroups, searchOpts);
  54. // create score map for sorting
  55. // key: id , value: score
  56. const scoreMap = {};
  57. for (const esPage of esResult.data) {
  58. scoreMap[esPage._id] = esPage._score;
  59. }
  60. const ids = esResult.data.map((page) => { return page._id });
  61. const findResult = await Page.findListByPageIds(ids);
  62. // add tag data to result pages
  63. findResult.pages.map((page) => {
  64. const data = esResult.data.find((data) => { return page.id === data._id });
  65. page._doc.tags = data._source.tag_names;
  66. return page;
  67. });
  68. result.meta = esResult.meta;
  69. result.totalCount = findResult.totalCount;
  70. result.data = findResult.pages
  71. .map((page) => {
  72. page.bookmarkCount = (page._source && page._source.bookmark_count) || 0;
  73. return page;
  74. })
  75. .sort((page1, page2) => {
  76. // note: this do not consider NaN
  77. return scoreMap[page2._id] - scoreMap[page1._id];
  78. });
  79. }
  80. catch (err) {
  81. return res.json(ApiResponse.error(err));
  82. }
  83. return res.json(ApiResponse.success(result));
  84. };
  85. actions.api = api;
  86. return actions;
  87. };