reports_controller.rb 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. # Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
  2. class ReportsController < ApplicationController
  3. prepend_before_action { authentication_check && authorize! }
  4. # GET /api/reports/config
  5. def reporting_config
  6. if !Report.enabled?
  7. render json: {
  8. error: __('Elasticsearch needs to be configured!'),
  9. }
  10. return
  11. end
  12. render json: {
  13. config: Report.config,
  14. profiles: Report::Profile.list,
  15. }
  16. end
  17. # GET /api/reports/generate
  18. def generate
  19. get_params = params_all
  20. return if !get_params
  21. result = {}
  22. get_params[:metric][:backend].each do |backend|
  23. condition = get_params[:profile].condition
  24. if backend[:condition]
  25. backend[:condition].merge(condition)
  26. else
  27. backend[:condition] = condition
  28. end
  29. next if !backend[:adapter]
  30. result[backend[:name]] = backend[:adapter].aggs(
  31. range_start: get_params[:start],
  32. range_end: get_params[:stop],
  33. interval: get_params[:range],
  34. selector: backend[:condition],
  35. params: backend[:params],
  36. timezone: get_params[:timezone],
  37. timezone_offset: get_params[:timezone_offset],
  38. current_user: current_user
  39. )
  40. end
  41. render json: {
  42. data: result
  43. }
  44. end
  45. # GET /api/reports/sets
  46. def sets
  47. get_params = params_all
  48. return if !get_params
  49. if !params[:downloadBackendSelected]
  50. render json: {
  51. error: __("Required parameter 'downloadBackendSelected' is missing."),
  52. }, status: :unprocessable_entity
  53. return
  54. end
  55. # get data
  56. result = {}
  57. excel = nil
  58. filename = nil
  59. get_params[:metric][:backend].each do |backend|
  60. next if params[:downloadBackendSelected] != backend[:name]
  61. condition = get_params[:profile].condition
  62. if backend[:condition]
  63. backend[:condition].merge(condition)
  64. else
  65. backend[:condition] = condition
  66. end
  67. next if !backend[:adapter]
  68. result = backend[:adapter].items(
  69. range_start: get_params[:start],
  70. range_end: get_params[:stop],
  71. interval: get_params[:range],
  72. selector: backend[:condition],
  73. params: backend[:params],
  74. sheet: params[:sheet],
  75. timezone: get_params[:timezone],
  76. timezone_offset: get_params[:timezone_offset],
  77. current_user: current_user
  78. )
  79. result = { count: 0, ticket_ids: [] } if result.nil?
  80. # generate sheet
  81. if params[:sheet]
  82. excel = ExcelSheet::Ticket.new(
  83. title: "#{get_params[:profile].name} (#{backend[:display]})",
  84. ticket_ids: result[:ticket_ids],
  85. timezone: params[:timezone],
  86. locale: current_user.locale,
  87. )
  88. filename = "tickets-#{get_params[:profile].name}-#{backend[:display]}.xls"
  89. end
  90. break
  91. end
  92. if excel
  93. send_data(
  94. excel.content,
  95. filename: filename,
  96. type: 'application/vnd.ms-excel',
  97. disposition: 'attachment'
  98. )
  99. return
  100. end
  101. render json: result
  102. end
  103. def params_all
  104. profile = nil
  105. if !params[:profiles] && !params[:profile_id]
  106. raise Exceptions::UnprocessableEntity, __("Required parameter 'profile' is missing.")
  107. end
  108. if params[:profile_id]
  109. profile = Report::Profile.find(params[:profile_id])
  110. else
  111. params[:profiles].each do |profile_id, active|
  112. next if !active
  113. profile = Report::Profile.find(profile_id)
  114. end
  115. end
  116. if !profile
  117. raise Exceptions::UnprocessableEntity, __('The active reporting profile could not be found.')
  118. end
  119. local_config = Report.config
  120. if !local_config || !local_config[:metric] || !local_config[:metric][params[:metric].to_sym]
  121. raise Exceptions::UnprocessableEntity, "Could not find metric #{params[:metric]}"
  122. end
  123. metric = local_config[:metric][params[:metric].to_sym]
  124. case params[:timeRange]
  125. when 'realtime'
  126. start_at = 60.minutes.ago
  127. stop_at = Time.zone.now
  128. range = 'minute'
  129. when 'day'
  130. date = Date.parse("#{params[:year]}-#{params[:month]}-#{params[:day]}").to_s
  131. start_at = Time.zone.parse("#{date}T00:00:00Z")
  132. stop_at = Time.zone.parse("#{date}T23:59:59Z")
  133. range = 'hour'
  134. when 'week'
  135. start_week_at = Date.commercial(params[:year].to_i, params[:week].to_i)
  136. stop_week_at = start_week_at.end_of_week
  137. start_at = Time.zone.parse("#{start_week_at.year}-#{start_week_at.month}-#{start_week_at.day}T00:00:00Z")
  138. stop_at = Time.zone.parse("#{stop_week_at.year}-#{stop_week_at.month}-#{stop_week_at.day}T23:59:59Z")
  139. range = 'week'
  140. when 'month'
  141. start_at = Time.zone.parse("#{params[:year]}-#{params[:month]}-01T00:00:00Z")
  142. stop_at = Time.zone.parse("#{params[:year]}-#{params[:month]}-#{start_at.end_of_month.day}T23:59:59Z")
  143. range = 'day'
  144. else
  145. start_at = Time.zone.parse("#{params[:year]}-01-01T00:00:00Z")
  146. stop_at = Time.zone.parse("#{params[:year]}-12-31T23:59:59Z")
  147. range = 'month'
  148. end
  149. params[:timezone] ||= Setting.get('timezone_default_sanitized')
  150. if params[:timeRange] != 'realtime'
  151. offset = stop_at.in_time_zone(params[:timezone]).utc_offset
  152. start_at -= offset
  153. stop_at -= offset
  154. end
  155. {
  156. profile: profile,
  157. metric: metric,
  158. config: local_config,
  159. start: start_at,
  160. stop: stop_at,
  161. range: range,
  162. timezone: params[:timezone],
  163. timezone_offset: offset,
  164. }
  165. end
  166. end