0
0
Fork 1
Spiegel von https://github.com/paviliondev/discourse-custom-wizard.git synchronisiert 2024-11-25 02:30:28 +01:00
discourse-custom-wizard/lib/custom_wizard/mapper.rb

270 Zeilen
6,1 KiB
Ruby

2021-03-11 07:30:15 +01:00
# frozen_string_literal: true
2020-03-30 08:16:03 +02:00
class CustomWizard::Mapper
attr_accessor :inputs, :data, :user
2021-03-11 07:30:15 +01:00
2024-10-16 13:52:03 +02:00
USER_FIELDS = %w[name username date_of_birth title locale trust_level email]
USER_OPTION_FIELDS = %w[email_level email_messages_level email_digests]
PROFILE_FIELDS = %w[location website bio_raw]
2021-03-11 07:30:15 +01:00
2020-04-07 15:33:11 +02:00
def self.user_fields
USER_FIELDS + USER_OPTION_FIELDS + PROFILE_FIELDS
2020-04-07 15:33:11 +02:00
end
2021-03-11 07:30:15 +01:00
2020-04-01 07:03:26 +02:00
OPERATORS = {
2024-10-16 13:52:03 +02:00
equal: "==",
2023-05-03 11:01:54 +02:00
not_equal: "!=",
2024-10-16 13:52:03 +02:00
greater: ">",
less: "<",
greater_or_equal: ">=",
less_or_equal: "<=",
regex: "=~",
2020-05-01 11:12:58 +02:00
is: {
present: "present?",
true: "==",
2024-10-16 13:52:03 +02:00
false: "==",
},
2020-04-01 07:03:26 +02:00
}
2021-03-11 07:30:15 +01:00
2020-03-30 08:16:03 +02:00
def initialize(params)
@inputs = params[:inputs] || {}
2023-03-21 17:38:53 +01:00
@data = params[:data] ? params[:data].with_indifferent_access : {}
2020-03-30 08:16:03 +02:00
@user = params[:user]
@opts = params[:opts] || {}
end
2021-03-11 07:30:15 +01:00
2020-04-06 10:36:38 +02:00
def perform
2020-03-30 08:16:03 +02:00
multiple = @opts[:multiple]
2020-04-06 10:36:38 +02:00
perform_result = multiple ? [] : nil
2021-03-11 07:30:15 +01:00
2020-03-30 08:16:03 +02:00
inputs.each do |input|
2024-10-16 13:52:03 +02:00
input_type = input["type"]
pairs = input["pairs"]
2021-03-11 07:30:15 +01:00
2024-10-16 13:52:03 +02:00
if (input_type === "conditional" && validate_pairs(pairs)) || input_type === "assignment"
output = input["output"]
output_type = input["output_type"]
2021-03-11 07:30:15 +01:00
2020-04-06 10:36:38 +02:00
result = build_result(map_field(output, output_type), input_type)
2021-03-11 07:30:15 +01:00
2020-03-30 08:16:03 +02:00
if multiple
2020-04-06 10:36:38 +02:00
perform_result.push(result)
2020-03-30 08:16:03 +02:00
else
2020-04-06 10:36:38 +02:00
perform_result = result
2020-03-30 08:16:03 +02:00
break
end
end
2021-03-11 07:30:15 +01:00
2024-10-16 13:52:03 +02:00
if input_type === "validation"
2020-04-06 10:36:38 +02:00
result = build_result(validate_pairs(pairs), input_type)
2021-03-11 07:30:15 +01:00
2020-04-06 10:36:38 +02:00
if multiple
perform_result.push(result)
2020-03-30 08:16:03 +02:00
else
2020-04-06 10:36:38 +02:00
perform_result = result
break
end
end
2021-03-11 07:30:15 +01:00
2024-10-16 13:52:03 +02:00
if input_type === "association"
2020-04-06 10:36:38 +02:00
result = build_result(map_pairs(pairs), input_type)
2021-03-11 07:30:15 +01:00
2020-04-06 10:36:38 +02:00
if multiple
perform_result.push(result)
else
perform_result = result
2020-03-30 08:16:03 +02:00
break
end
end
end
2021-03-11 07:30:15 +01:00
2020-04-06 10:36:38 +02:00
perform_result
end
2021-03-11 07:30:15 +01:00
2020-04-06 10:36:38 +02:00
def build_result(result, type)
2020-04-07 09:54:30 +02:00
if @opts[:with_type]
2024-10-16 13:52:03 +02:00
{ type: type, result: result }
2020-04-06 10:36:38 +02:00
else
result
end
2020-03-30 08:16:03 +02:00
end
2021-03-11 07:30:15 +01:00
2020-03-30 08:16:03 +02:00
def validate_pairs(pairs)
2020-04-23 04:52:25 +02:00
pairs.all? do |pair|
2024-10-16 13:52:03 +02:00
connector = pair["connector"]
2020-04-07 09:54:30 +02:00
operator = map_operator(connector)
2024-10-16 13:52:03 +02:00
key = map_field(pair["key"], pair["key_type"])
value = cast_value(map_field(pair["value"], pair["value_type"]), key, connector)
2020-04-01 07:03:26 +02:00
begin
validation_result(key, value, operator)
2020-04-01 14:16:26 +02:00
rescue NoMethodError
#
2020-04-01 07:03:26 +02:00
end
2020-03-30 08:16:03 +02:00
end
end
2021-03-11 07:30:15 +01:00
2020-04-30 11:17:37 +02:00
def cast_value(value, key, connector)
2024-10-16 13:52:03 +02:00
if connector == "regex"
2020-04-07 13:53:00 +02:00
Regexp.new(value)
else
if key.is_a?(String)
value.to_s
elsif key.is_a?(Integer)
value.to_i
else
value
end
end
end
2021-03-11 07:30:15 +01:00
def validation_result(key, value, operator)
result = nil
2021-03-11 07:30:15 +01:00
if operator.is_a?(Hash) && (operator = operator[value.to_sym]).present?
if value == "present"
result = key.public_send(operator)
2024-10-16 13:52:03 +02:00
elsif %w[true false].include?(value)
result = bool(key).public_send(operator, bool(value))
end
elsif [key, value, operator].all? { |i| !i.nil? }
result = key.public_send(operator, value)
else
result = false
end
2021-03-11 07:30:15 +01:00
2024-10-16 13:52:03 +02:00
if operator == "=~"
2020-11-03 01:24:20 +01:00
result.nil? ? false : true
2020-04-07 09:54:30 +02:00
else
result
end
end
2021-03-11 07:30:15 +01:00
2020-04-06 10:36:38 +02:00
def map_pairs(pairs)
result = []
2021-03-11 07:30:15 +01:00
2020-04-06 10:36:38 +02:00
pairs.each do |pair|
2024-10-16 13:52:03 +02:00
key = map_field(pair["key"], pair["key_type"])
value = map_field(pair["value"], pair["value_type"])
result.push(key: key, value: value) if key && value
2020-04-06 10:36:38 +02:00
end
2021-03-11 07:30:15 +01:00
2020-04-06 10:36:38 +02:00
result
end
2021-03-11 07:30:15 +01:00
2020-04-06 10:36:38 +02:00
def map_operator(connector)
2024-10-16 13:52:03 +02:00
OPERATORS[connector.to_sym] || "=="
2020-03-30 08:16:03 +02:00
end
2021-03-11 07:30:15 +01:00
2020-03-30 08:16:03 +02:00
def map_field(value, type)
2020-04-02 10:21:03 +02:00
method = "map_#{type}"
2021-03-11 07:30:15 +01:00
2020-03-30 08:16:03 +02:00
if self.respond_to?(method)
self.send(method, value)
else
value
end
end
2021-03-11 07:30:15 +01:00
2020-04-13 14:17:22 +02:00
def map_text(value)
interpolate(value)
end
2021-03-11 07:30:15 +01:00
2020-04-07 10:33:51 +02:00
def map_wizard_field(value)
2020-03-30 08:16:03 +02:00
data && !data.key?("submitted_at") && data[value]
end
2021-03-11 07:30:15 +01:00
def map_wizard_action(value)
data && !data.key?("submitted_at") && data[value]
end
2020-03-30 08:16:03 +02:00
2020-04-02 10:21:03 +02:00
def map_user_field(value)
2023-01-18 19:53:36 +01:00
return nil unless user
if value.include?(User::USER_FIELD_PREFIX)
user.custom_fields[value]
2020-03-30 08:16:03 +02:00
elsif PROFILE_FIELDS.include?(value)
user.user_profile.send(value)
2020-03-30 08:16:03 +02:00
elsif USER_FIELDS.include?(value)
user.send(value)
elsif USER_OPTION_FIELDS.include?(value)
user.user_option.send(value)
2024-10-16 13:52:03 +02:00
elsif value.include?("avatar")
2022-12-12 13:19:04 +01:00
get_avatar_url(value)
else
nil
2020-03-30 08:16:03 +02:00
end
end
2021-03-11 07:30:15 +01:00
def map_user_field_options(value)
if value.include?(User::USER_FIELD_PREFIX)
2024-10-16 13:52:03 +02:00
if field = UserField.find_by(id: value.split("_").last)
field.user_field_options.map(&:value)
end
end
end
2021-03-11 07:30:15 +01:00
def interpolate(string, opts = { user: true, wizard: true, value: true, template: false })
return string if string.blank? || string.frozen?
2021-03-11 07:30:15 +01:00
2024-10-16 13:52:03 +02:00
string.gsub!(/u\{(.*?)\}/) { |match| map_user_field($1) || "" } if opts[:user] && @user.present?
2021-03-11 07:30:15 +01:00
2024-10-16 13:52:03 +02:00
string.gsub!(/w\{(.*?)\}/) { |match| recurse(data, [*$1.split(".")]) || "" } if opts[:wizard]
2021-03-11 07:30:15 +01:00
2020-04-16 07:14:03 +02:00
if opts[:value]
string.gsub!(/v\{(.*?)\}/) do |match|
2024-10-16 13:52:03 +02:00
attrs = $1.split(":")
2020-04-16 07:14:03 +02:00
key = attrs.first
format = attrs.last if attrs.length > 1
2024-10-16 13:52:03 +02:00
result = ""
2021-03-11 07:30:15 +01:00
2024-10-16 13:52:03 +02:00
if key == "time"
2020-04-16 07:14:03 +02:00
time_format = format.present? ? format : "%B %-d, %Y"
result = Time.now.strftime(time_format)
end
2020-03-30 08:16:03 +02:00
2020-04-16 07:14:03 +02:00
result
end
2020-03-30 08:16:03 +02:00
end
2021-03-11 07:30:15 +01:00
if opts[:template] #&& CustomWizard::Subscription.subscribed?
template = Liquid::Template.parse(string)
string = template.render(data)
end
2020-04-16 07:14:03 +02:00
string
2020-03-30 08:16:03 +02:00
end
2021-03-11 07:30:15 +01:00
2020-03-30 08:16:03 +02:00
def recurse(data, keys)
2020-07-22 03:39:30 +02:00
return nil if data.nil?
2020-03-30 08:16:03 +02:00
k = keys.shift
result = data[k]
if keys.empty?
2023-03-21 17:38:53 +01:00
result.is_a?(Hash) ? "" : result
else
self.recurse(result, keys)
end
2020-03-30 08:16:03 +02:00
end
def bool(value)
ActiveRecord::Type::Boolean.new.cast(value)
end
2022-12-12 13:19:04 +01:00
def get_avatar_url(value)
2024-10-16 13:52:03 +02:00
parts = value.split(".")
2022-12-12 13:19:04 +01:00
valid_sizes = Discourse.avatar_sizes.to_a
2024-10-16 13:52:03 +02:00
if value === "avatar" || parts.size === 1 || valid_sizes.exclude?(parts.last.to_i)
2022-12-12 13:19:04 +01:00
user.small_avatar_url
else
user.avatar_template_url.gsub("{size}", parts.last)
end
end
def self.mapped_value?(value)
value.is_a?(Array) && value.all? { |v| v.is_a?(Hash) && v.key?("type") }
end
end