search_controller.rb 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. # Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
  2. class SearchController < ApplicationController
  3. prepend_before_action :authentication_check
  4. # GET|POST /api/v1/search
  5. # GET|POST /api/v1/search/:objects
  6. def search_generic
  7. # get params
  8. query = params[:query]
  9. if query.respond_to?(:permit!)
  10. query = query.permit!.to_h
  11. end
  12. limit = params[:limit] || 10
  13. # convert objects string into array of class names
  14. # e.g. user-ticket-another_object = %w( User Ticket AnotherObject )
  15. objects = if params[:objects]
  16. params[:objects].split('-').map(&:camelize)
  17. else
  18. Setting.get('models_searchable')
  19. end
  20. # get priorities of result
  21. objects_in_order = []
  22. objects_in_order_hash = {}
  23. objects.each do |object|
  24. local_class = object.constantize
  25. preferences = local_class.search_preferences(current_user)
  26. next if !preferences
  27. objects_in_order_hash[preferences[:prio]] = local_class
  28. end
  29. objects_in_order_hash.keys.sort.reverse_each do |prio|
  30. objects_in_order.push objects_in_order_hash[prio]
  31. end
  32. generic_search_params = {
  33. query: query,
  34. limit: limit,
  35. current_user: current_user,
  36. }
  37. # try search index backend
  38. assets = {}
  39. result = []
  40. if SearchIndexBackend.enabled?
  41. # get direct search index based objects
  42. objects_with_direct_search_index = []
  43. objects_without_direct_search_index = []
  44. objects.each do |object|
  45. preferences = object.constantize.search_preferences(current_user)
  46. next if !preferences
  47. if preferences[:direct_search_index]
  48. objects_with_direct_search_index.push object
  49. else
  50. objects_without_direct_search_index.push object
  51. end
  52. end
  53. # do only one query to index search backend
  54. if objects_with_direct_search_index.present?
  55. items = SearchIndexBackend.search(query, objects_with_direct_search_index, limit: limit)
  56. items.each do |item|
  57. local_class = item[:type].constantize
  58. record = local_class.lookup(id: item[:id])
  59. next if !record
  60. assets = record.assets(assets)
  61. item[:type] = local_class.to_app_model.to_s
  62. result.push item
  63. end
  64. end
  65. # e. g. do ticket query by Ticket class to handle ticket permissions
  66. objects_without_direct_search_index.each do |object|
  67. object_result = search_generic_backend(object.constantize, assets, generic_search_params)
  68. if object_result.present?
  69. result.concat(object_result)
  70. end
  71. end
  72. # sort order by object priority
  73. result_in_order = []
  74. objects_in_order.each do |object|
  75. result.each do |item|
  76. next if item[:type] != object.to_app_model.to_s
  77. item[:id] = item[:id].to_i
  78. result_in_order.push item
  79. end
  80. end
  81. result = result_in_order
  82. else
  83. # do query
  84. objects_in_order.each do |object|
  85. object_result = search_generic_backend(object, assets, generic_search_params)
  86. if object_result.present?
  87. result.concat(object_result)
  88. end
  89. end
  90. end
  91. render json: {
  92. assets: assets,
  93. result: result,
  94. }
  95. end
  96. private
  97. =begin
  98. search generic backend
  99. SearchController#search_generic_backend(
  100. Ticket, # object
  101. {}, # assets
  102. query: "search query",
  103. limit: 10,
  104. current_user: user,
  105. )
  106. =end
  107. def search_generic_backend(object, assets, params)
  108. found_objects = object.search(params)
  109. result = []
  110. found_objects.each do |found_object|
  111. item = {
  112. id: found_object.id,
  113. type: found_object.class.to_app_model.to_s
  114. }
  115. result.push item
  116. assets = found_object.assets(assets)
  117. end
  118. result
  119. end
  120. end