reports_controller.rb 5.6 KB

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