reports_controller.rb 5.8 KB

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