|
class ReportComposer
|
|
include ActiveModel::Model
|
|
|
|
class InputValue
|
|
include ActiveModel::Model
|
|
|
|
attr_accessor :value, :template_input
|
|
|
|
validates :value, :presence => true, :if => proc { |v| v.template_input.required? || v.value.present? }
|
|
|
|
validates :value, :inclusion => { :in => proc { |v| options_for_template_input v.template_input } },
|
|
:if => proc { |v| v.template_input.input_type == 'user' && v.template_input.options_array.present? }
|
|
|
|
class << self
|
|
private
|
|
|
|
def options_for_template_input(template_input)
|
|
options = template_input.options_array
|
|
options += [''] unless template_input.required?
|
|
options
|
|
end
|
|
end
|
|
end
|
|
|
|
class ParamParser
|
|
attr_reader :raw_params
|
|
|
|
def mail_to
|
|
raw_params[:mail_to]
|
|
end
|
|
|
|
def gzip?
|
|
raw_params[:gzip].nil? ? send_mail? : !!raw_params[:gzip]
|
|
end
|
|
|
|
def send_mail?
|
|
raw_params['send_mail'].to_s == '1'
|
|
end
|
|
|
|
def generate_at
|
|
raw_params['generate_at']&.to_time
|
|
end
|
|
|
|
def params
|
|
{ template_id: raw_params[:id],
|
|
generate_at: generate_at,
|
|
gzip: gzip?,
|
|
send_mail: send_mail?,
|
|
mail_to: mail_to }.with_indifferent_access
|
|
end
|
|
end
|
|
|
|
class UiParams < ParamParser
|
|
def initialize(raw_params)
|
|
@raw_params = raw_params.permit!
|
|
end
|
|
|
|
def send_mail?
|
|
report_base_params['send_mail'].to_s == '1'
|
|
end
|
|
|
|
def mail_to
|
|
report_base_params[:mail_to]
|
|
end
|
|
|
|
def generate_at
|
|
Time.zone.parse(report_base_params['generate_at']) if report_base_params['generate_at'].present?
|
|
end
|
|
|
|
def params
|
|
super.merge(input_values: report_base_params[:input_values])
|
|
end
|
|
|
|
def report_base_params
|
|
(raw_params[:report_template_report] || {}).to_hash.with_indifferent_access
|
|
end
|
|
end
|
|
|
|
class ApiParams < ParamParser
|
|
def initialize(raw_params)
|
|
@raw_params = raw_params.permit!
|
|
end
|
|
|
|
def send_mail?
|
|
!!mail_to
|
|
end
|
|
|
|
def generate_at
|
|
Time.find_zone("UTC").parse(raw_params['generate_at']) if raw_params['generate_at'].present?
|
|
end
|
|
|
|
def params
|
|
super.merge(
|
|
input_values: convert_input_names_to_ids(
|
|
raw_params[:id],
|
|
(raw_params[:input_values] || {}).to_hash
|
|
)
|
|
)
|
|
end
|
|
|
|
def convert_input_names_to_ids(template_id, input_values)
|
|
inputs = TemplateInput.where(:template_id => template_id, :name => input_values.keys)
|
|
Hash[inputs.map { |i| [ i.id.to_s, 'value' => input_values[i.name] ] }]
|
|
end
|
|
end
|
|
|
|
class MailToValidator < ActiveModel::EachValidator
|
|
MAIL_DELIMITER = ','
|
|
|
|
def validate_each(model, attribute, value)
|
|
return if value.empty?
|
|
value.split(MAIL_DELIMITER).each do |mail|
|
|
mail_validator.validate_each(model, attribute, mail.strip)
|
|
end
|
|
end
|
|
|
|
def mail_validator
|
|
@mail_validator ||= EmailValidator.new(attributes: attributes)
|
|
end
|
|
end
|
|
|
|
attr_reader :template, :generate_at
|
|
|
|
validates :mail_to, mail_to: true, if: :send_mail?
|
|
|
|
def initialize(params)
|
|
@params = params.with_indifferent_access
|
|
@generate_at = @params.delete('generate_at')
|
|
@template = load_report_template(@params[:template_id])
|
|
@input_values = build_inputs(@template, @params[:input_values])
|
|
end
|
|
|
|
def self.from_ui_params(ui_params)
|
|
self.new(UiParams.new(ui_params).params)
|
|
end
|
|
|
|
def self.from_api_params(api_params)
|
|
self.new(ApiParams.new(api_params).params)
|
|
end
|
|
|
|
def build_inputs(template, input_values)
|
|
inputs = {}.with_indifferent_access
|
|
return inputs if template.nil?
|
|
|
|
# process values from params (including empty hash)
|
|
template.template_inputs.each do |input|
|
|
val = input_values[input.id.to_s].try(:[], 'value') unless input_values.nil?
|
|
val = input.default if val.blank?
|
|
inputs[input.id.to_s] = InputValue.new(value: val, template_input: input)
|
|
end
|
|
|
|
inputs
|
|
end
|
|
|
|
def to_param
|
|
@params.to_param
|
|
end
|
|
|
|
def to_params
|
|
@params
|
|
end
|
|
|
|
def valid?
|
|
res = super & @input_values.map { |_, input_value| input_value.valid? }.all?
|
|
merge_input_errors unless res
|
|
res
|
|
end
|
|
|
|
def template_input_values
|
|
Hash[@input_values.map { |_, input_value| [input_value.template_input.name, input_value.value] }]
|
|
end
|
|
|
|
def input_value_for(input)
|
|
@input_values[input.id.to_s]
|
|
end
|
|
|
|
def load_report_template(id)
|
|
ReportTemplate.authorized(:generate_report_templates).find_by_id(id)
|
|
end
|
|
|
|
def gzip?
|
|
!!@params['gzip']
|
|
end
|
|
|
|
def mime_type
|
|
gzip? ? :gzip : :text
|
|
end
|
|
|
|
def send_mail?
|
|
!!@params['send_mail']
|
|
end
|
|
alias_method :send_mail, :send_mail?
|
|
|
|
def mail_to
|
|
@params['mail_to'] || User.current.mail
|
|
end
|
|
|
|
def report_filename
|
|
name = @template.suggested_report_name.to_s
|
|
name += '.gz' if gzip?
|
|
name
|
|
end
|
|
|
|
def schedule_rendering
|
|
scheduler = TemplateRenderJob
|
|
if generate_at
|
|
scheduler = scheduler.set(wait_until: generate_at)
|
|
end
|
|
scheduler.perform_later(self.to_params, user_id: User.current.id)
|
|
end
|
|
|
|
def render(mode: Foreman::Renderer::REAL_MODE, **params)
|
|
result = @template.render(mode: mode, template_input_values: template_input_values, **params)
|
|
result = ActiveSupport::Gzip.compress(result) if gzip?
|
|
result
|
|
end
|
|
|
|
private
|
|
|
|
def merge_input_errors
|
|
@input_values.each do |id, input_value|
|
|
input_value.errors.full_messages.each do |message|
|
|
errors.add :base, (_("Input %s: ") % input_value.template_input.name) + message
|
|
end
|
|
end
|
|
end
|
|
end
|