2020-03-30 08:16:03 +02:00
|
|
|
class CustomWizard::Mapper
|
|
|
|
attr_accessor :inputs, :data, :user
|
|
|
|
|
2020-04-10 10:51:01 +02:00
|
|
|
USER_FIELDS = ['name', 'username', 'email', 'date_of_birth', 'title', 'locale', 'trust_level']
|
2020-03-30 08:16:03 +02:00
|
|
|
PROFILE_FIELDS = ['location', 'website', 'bio_raw']
|
2020-05-23 00:42:26 +02:00
|
|
|
CATEGORY_NOTIFICATION_LEVELS = ['regular','watching', 'tracking', 'watching_first_post','muted']
|
2020-04-07 15:33:11 +02:00
|
|
|
|
|
|
|
def self.user_fields
|
|
|
|
USER_FIELDS + PROFILE_FIELDS
|
|
|
|
end
|
|
|
|
|
2020-04-01 07:03:26 +02:00
|
|
|
OPERATORS = {
|
2020-04-01 14:16:26 +02:00
|
|
|
equal: '==',
|
2020-04-01 07:03:26 +02:00
|
|
|
greater: '>',
|
|
|
|
less: '<',
|
|
|
|
greater_or_equal: '>=',
|
2020-04-06 10:36:38 +02:00
|
|
|
less_or_equal: '<=',
|
2020-04-30 11:17:37 +02:00
|
|
|
regex: '=~',
|
2020-05-01 11:12:58 +02:00
|
|
|
is: {
|
2020-05-01 10:16:58 +02:00
|
|
|
present: "present?",
|
|
|
|
true: "==",
|
|
|
|
false: "=="
|
|
|
|
}
|
2020-04-01 07:03:26 +02:00
|
|
|
}
|
2020-03-30 08:16:03 +02:00
|
|
|
|
|
|
|
def initialize(params)
|
|
|
|
@inputs = params[:inputs] || {}
|
|
|
|
@data = params[:data] || {}
|
|
|
|
@user = params[:user]
|
|
|
|
@opts = params[:opts] || {}
|
|
|
|
end
|
|
|
|
|
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
|
2020-03-30 08:16:03 +02:00
|
|
|
|
|
|
|
inputs.each do |input|
|
2020-04-06 10:36:38 +02:00
|
|
|
input_type = input['type']
|
|
|
|
pairs = input['pairs']
|
|
|
|
|
|
|
|
if (input_type === 'conditional' && validate_pairs(pairs)) || input_type === 'assignment'
|
|
|
|
output = input['output']
|
|
|
|
output_type = input['output_type']
|
|
|
|
|
|
|
|
result = build_result(map_field(output, output_type), input_type)
|
2020-04-19 13:02:14 +02: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
|
|
|
|
|
2020-04-06 10:36:38 +02:00
|
|
|
if input_type === 'validation'
|
|
|
|
result = build_result(validate_pairs(pairs), input_type)
|
2020-03-30 08:16:03 +02: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
|
|
|
|
|
|
|
|
if input_type === 'association'
|
|
|
|
result = build_result(map_pairs(pairs), input_type)
|
|
|
|
|
|
|
|
if multiple
|
|
|
|
perform_result.push(result)
|
|
|
|
else
|
|
|
|
perform_result = result
|
2020-03-30 08:16:03 +02:00
|
|
|
break
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2020-04-07 10:33:51 +02:00
|
|
|
|
2020-04-06 10:36:38 +02:00
|
|
|
perform_result
|
|
|
|
end
|
|
|
|
|
|
|
|
def build_result(result, type)
|
2020-04-07 09:54:30 +02:00
|
|
|
if @opts[:with_type]
|
2020-04-06 10:36:38 +02:00
|
|
|
{
|
|
|
|
type: type,
|
|
|
|
result: result
|
|
|
|
}
|
|
|
|
else
|
|
|
|
result
|
|
|
|
end
|
2020-03-30 08:16:03 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
def validate_pairs(pairs)
|
2020-04-23 04:52:25 +02:00
|
|
|
pairs.all? do |pair|
|
2020-04-07 09:54:30 +02:00
|
|
|
connector = pair['connector']
|
|
|
|
operator = map_operator(connector)
|
2020-04-30 11:17:37 +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
|
2020-05-01 10:16:58 +02:00
|
|
|
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
|
|
|
|
|
2020-04-30 11:17:37 +02:00
|
|
|
def cast_value(value, key, connector)
|
2020-04-07 13:53:00 +02:00
|
|
|
if connector == 'regex'
|
|
|
|
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
|
2020-05-23 00:42:26 +02:00
|
|
|
|
2020-05-01 10:16:58 +02:00
|
|
|
def validation_result(key, value, operator)
|
|
|
|
result = nil
|
2020-05-23 00:42:26 +02:00
|
|
|
|
2020-05-01 10:16:58 +02:00
|
|
|
if operator.is_a?(Hash) && (operator = operator[value.to_sym]).present?
|
|
|
|
if value == "present"
|
|
|
|
result = key.public_send(operator)
|
|
|
|
elsif ["true", "false"].include?(value)
|
|
|
|
result = key.public_send(operator, ActiveRecord::Type::Boolean.new.cast(value))
|
|
|
|
end
|
|
|
|
else
|
|
|
|
result = key.public_send(operator, value)
|
|
|
|
end
|
|
|
|
|
|
|
|
if operator == '=~'
|
2020-04-07 09:54:30 +02:00
|
|
|
result == 0 ? true : false
|
|
|
|
else
|
|
|
|
result
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-04-06 10:36:38 +02:00
|
|
|
def map_pairs(pairs)
|
|
|
|
result = []
|
|
|
|
|
|
|
|
pairs.each do |pair|
|
|
|
|
key = map_field(pair['key'], pair['key_type'])
|
|
|
|
value = map_field(pair['value'], pair['value_type'])
|
|
|
|
|
|
|
|
if key && value
|
|
|
|
result.push(
|
|
|
|
key: key,
|
|
|
|
value: value
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
result
|
|
|
|
end
|
|
|
|
|
|
|
|
def map_operator(connector)
|
2020-04-01 07:03:26 +02:00
|
|
|
OPERATORS[connector.to_sym] || '=='
|
2020-03-30 08:16:03 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
def map_field(value, type)
|
2020-04-02 10:21:03 +02:00
|
|
|
method = "map_#{type}"
|
2020-03-30 08:16:03 +02:00
|
|
|
|
|
|
|
if self.respond_to?(method)
|
|
|
|
self.send(method, value)
|
|
|
|
else
|
|
|
|
value
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-04-13 14:17:22 +02:00
|
|
|
def map_text(value)
|
|
|
|
interpolate(value)
|
|
|
|
end
|
|
|
|
|
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
|
|
|
|
|
2020-04-02 10:21:03 +02:00
|
|
|
def map_user_field(value)
|
2020-04-19 13:02:14 +02:00
|
|
|
if value.include?(User::USER_FIELD_PREFIX)
|
2020-03-30 08:16:03 +02:00
|
|
|
UserCustomField.where(user_id: user.id, name: value).pluck(:value).first
|
|
|
|
elsif PROFILE_FIELDS.include?(value)
|
|
|
|
UserProfile.find_by(user_id: user.id).send(value)
|
|
|
|
elsif USER_FIELDS.include?(value)
|
|
|
|
User.find(user.id).send(value)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-04-19 13:02:14 +02:00
|
|
|
def map_user_field_options(value)
|
|
|
|
if value.include?(User::USER_FIELD_PREFIX)
|
|
|
|
if field = UserField.find(value.split('_').last)
|
|
|
|
field.user_field_options.map(&:value)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-04-16 07:14:03 +02:00
|
|
|
def interpolate(string, opts={ user: true, wizard: true, value: true })
|
|
|
|
return string if string.blank?
|
|
|
|
|
|
|
|
if opts[:user]
|
|
|
|
string.gsub!(/u\{(.*?)\}/) do |match|
|
|
|
|
result = ''
|
|
|
|
result = user.send($1) if USER_FIELDS.include?($1)
|
|
|
|
result = user.user_profile.send($1) if PROFILE_FIELDS.include?($1)
|
|
|
|
result
|
|
|
|
end
|
2020-03-30 08:16:03 +02:00
|
|
|
end
|
|
|
|
|
2020-04-16 07:14:03 +02:00
|
|
|
if opts[:wizard]
|
|
|
|
string.gsub!(/w\{(.*?)\}/) do |match|
|
|
|
|
value = recurse(data, [*$1.split('.')])
|
|
|
|
value.present? ? value : ''
|
2020-03-30 08:16:03 +02:00
|
|
|
end
|
2020-04-16 07:14:03 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
if opts[:value]
|
|
|
|
string.gsub!(/v\{(.*?)\}/) do |match|
|
|
|
|
attrs = $1.split(':')
|
|
|
|
key = attrs.first
|
|
|
|
format = attrs.last if attrs.length > 1
|
|
|
|
result = ''
|
|
|
|
|
2020-04-30 11:17:53 +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
|
2020-04-16 07:14:03 +02:00
|
|
|
|
|
|
|
string
|
2020-03-30 08:16:03 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
def recurse(data, keys)
|
|
|
|
k = keys.shift
|
|
|
|
result = data[k]
|
|
|
|
keys.empty? ? result : self.recurse(result, keys)
|
|
|
|
end
|
|
|
|
end
|