search_controller.rb 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. # Copyright (C) 2012-2016 Zammad Foundation, http://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. # enable search only for users with valid session
  8. if !current_user
  9. response_access_deny
  10. return true
  11. end
  12. # get params
  13. query = params[:query]
  14. limit = params[:limit] || 10
  15. # convert objects string into array of class names
  16. # e.g. user-ticket-another_object = %w( User Ticket AnotherObject )
  17. objects = if !params[:objects]
  18. Setting.get('models_searchable')
  19. else
  20. params[:objects].split('-').map(&:camelize)
  21. end
  22. # get priorities of result
  23. objects_in_order = []
  24. objects_in_order_hash = {}
  25. objects.each { |object|
  26. preferences = object.constantize.search_preferences(current_user)
  27. next if !preferences
  28. objects_in_order_hash[preferences[:prio]] = object
  29. }
  30. objects_in_order_hash.keys.sort.reverse_each { |prio|
  31. objects_in_order.push objects_in_order_hash[prio]
  32. }
  33. # try search index backend
  34. assets = {}
  35. result = []
  36. if SearchIndexBackend.enabled?
  37. # get direct search index based objects
  38. objects_with_direct_search_index = []
  39. objects_without_direct_search_index = []
  40. objects.each { |object|
  41. preferences = object.constantize.search_preferences(current_user)
  42. next if !preferences
  43. if preferences[:direct_search_index]
  44. objects_with_direct_search_index.push object
  45. else
  46. objects_without_direct_search_index.push object
  47. end
  48. }
  49. # do only one query to index search backend
  50. if !objects_with_direct_search_index.empty?
  51. items = SearchIndexBackend.search(query, limit, objects_with_direct_search_index)
  52. items.each { |item|
  53. require item[:type].to_filename
  54. record = Kernel.const_get(item[:type]).lookup(id: item[:id])
  55. assets = record.assets(assets)
  56. result.push item
  57. }
  58. end
  59. # e. g. do ticket query by Ticket class to handle ticket permissions
  60. objects_without_direct_search_index.each { |object|
  61. object_result = search_generic_backend(object, query, limit, current_user, assets)
  62. if !object_result.empty?
  63. result = result.concat(object_result)
  64. end
  65. }
  66. # sort order by object priority
  67. result_in_order = []
  68. objects_in_order.each { |object|
  69. result.each { |item|
  70. next if item[:type] != object
  71. item[:id] = item[:id].to_i
  72. result_in_order.push item
  73. }
  74. }
  75. result = result_in_order
  76. else
  77. # do query
  78. objects_in_order.each { |object|
  79. object_result = search_generic_backend(object, query, limit, current_user, assets)
  80. if !object_result.empty?
  81. result = result.concat(object_result)
  82. end
  83. }
  84. end
  85. render json: {
  86. assets: assets,
  87. result: result,
  88. }
  89. end
  90. private
  91. def search_generic_backend(object, query, limit, current_user, assets)
  92. found_objects = object.constantize.search(
  93. query: query,
  94. limit: limit,
  95. current_user: current_user,
  96. )
  97. result = []
  98. found_objects.each do |found_object|
  99. item = {
  100. id: found_object.id,
  101. type: found_object.class.to_s
  102. }
  103. result.push item
  104. assets = found_object.assets(assets)
  105. end
  106. result
  107. end
  108. end