1
0
Fork 0
discourse-custom-wizard-unl.../lib/custom_wizard/validators/template.rb
2022-03-12 15:08:56 +01:00

185 Zeilen
4,8 KiB
Ruby

# frozen_string_literal: true
class CustomWizard::TemplateValidator
include HasErrors
include ActiveModel::Model
def initialize(data, opts = {})
@data = data
@opts = opts
@subscription = CustomWizard::Subscription.new
end
def perform
data = @data
check_id(data, :wizard)
check_required(data, :wizard)
validate_after_signup
validate_after_time
validate_subscription(data, :wizard)
return false if errors.any?
data[:steps].each do |step|
check_required(step, :step)
validate_subscription(step, :step)
validate_liquid_template(step, :step)
if step[:fields].present?
step[:fields].each do |field|
validate_subscription(field, :field)
check_required(field, :field)
validate_liquid_template(field, :field)
end
end
end
if data[:actions].present?
data[:actions].each do |action|
validate_subscription(action, :action)
check_required(action, :action)
validate_liquid_template(action, :action)
end
end
!errors.any?
end
def self.required
{
wizard: ['id', 'name', 'steps'],
step: ['id'],
field: ['id', 'type'],
action: ['id', 'type']
}
end
def self.subscription
{
wizard: {
save_submissions: 'false',
restart_on_revisit: 'true',
},
step: {
condition: 'present',
index: 'conditional',
required_data: 'present',
permitted_params: 'present'
},
field: {
condition: 'present',
index: 'conditional'
},
action: {
type: %w[
send_message
add_to_group
create_category
create_group
send_to_api
]
}
}
end
private
def check_required(object, type)
self.class.required[type].each do |property|
if object[property].blank?
errors.add :base, I18n.t("wizard.validation.required", property: property)
end
end
end
def validate_subscription(object, type)
self.class.subscription[type].each do |property, subscription_type|
val = object[property.to_s]
is_subscription = (val != nil) && (
subscription_type === 'present' && val.present? ||
(['true', 'false'].include?(subscription_type) && cast_bool(val) == cast_bool(subscription_type)) ||
(subscription_type === 'conditional' && val.is_a?(Hash)) ||
(subscription_type.is_a?(Array) && subscription_type.include?(val))
)
if is_subscription && !@subscription.subscribed?
errors.add :base, I18n.t("wizard.validation.subscription", type: type.to_s, property: property)
end
end
end
def check_id(object, type)
if type === :wizard && @opts[:create] && CustomWizard::Template.exists?(object[:id])
errors.add :base, I18n.t("wizard.validation.conflict", wizard_id: object[:id])
end
end
def validate_after_signup
return unless ActiveRecord::Type::Boolean.new.cast(@data[:after_signup])
other_after_signup = CustomWizard::Template.list(setting: 'after_signup')
.select { |template| template['id'] != @data[:id] }
if other_after_signup.any?
errors.add :base, I18n.t("wizard.validation.after_signup", wizard_id: other_after_signup.first['id'])
end
end
def validate_after_time
return unless ActiveRecord::Type::Boolean.new.cast(@data[:after_time])
if ActiveRecord::Type::Boolean.new.cast(@data[:after_signup])
errors.add :base, I18n.t("wizard.validation.after_signup_after_time")
return
end
wizard = CustomWizard::Wizard.create(@data[:id]) if !@opts[:create]
current_time = wizard.present? ? wizard.after_time_scheduled : nil
new_time = @data[:after_time_scheduled]
begin
active_time = Time.parse(new_time.present? ? new_time : current_time).utc
rescue ArgumentError
invalid_time = true
end
if invalid_time || active_time.blank? || active_time < Time.now.utc
errors.add :base, I18n.t("wizard.validation.after_time")
end
end
def cast_bool(val)
ActiveRecord::Type::Boolean.new.cast(val)
end
def validate_liquid_template(object, type)
%w[
description
raw_description
placeholder
preview_template
post_template
].each do |field|
if template = object[field]
result = is_liquid_template_valid?(template)
unless "valid" == result
error = I18n.t("wizard.validation.liquid_syntax_error",
attribute: "#{object[:id]}.#{field}",
message: result
)
errors.add :base, error
end
end
end
end
def is_liquid_template_valid?(template)
begin
Liquid::Template.parse(template)
'valid'
rescue Liquid::SyntaxError => error
error.message
end
end
end