2024-02-16 09:35:16 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
class ThemeSettingsObjectValidator
|
2024-02-21 08:11:15 +08:00
|
|
|
def initialize(schema:, object:, valid_category_ids: nil)
|
2024-02-16 09:35:16 +08:00
|
|
|
@object = object
|
|
|
|
@schema_name = schema[:name]
|
|
|
|
@properties = schema[:properties]
|
|
|
|
@errors = {}
|
2024-02-21 08:11:15 +08:00
|
|
|
@valid_category_ids = valid_category_ids
|
2024-02-16 09:35:16 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def validate
|
2024-02-19 13:19:35 +08:00
|
|
|
validate_properties
|
2024-02-16 09:35:16 +08:00
|
|
|
|
|
|
|
@properties.each do |property_name, property_attributes|
|
|
|
|
if property_attributes[:type] == "objects"
|
|
|
|
@object[property_name]&.each do |child_object|
|
|
|
|
@errors[property_name] ||= []
|
|
|
|
|
|
|
|
@errors[property_name].push(
|
2024-02-21 08:11:15 +08:00
|
|
|
self
|
|
|
|
.class
|
|
|
|
.new(schema: property_attributes[:schema], object: child_object, valid_category_ids:)
|
|
|
|
.validate,
|
2024-02-16 09:35:16 +08:00
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
@errors
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2024-02-19 13:19:35 +08:00
|
|
|
def validate_properties
|
2024-02-16 09:35:16 +08:00
|
|
|
@properties.each do |property_name, property_attributes|
|
2024-02-21 08:11:15 +08:00
|
|
|
next if property_attributes[:type] == "objects"
|
2024-02-20 09:17:27 +08:00
|
|
|
next if property_attributes[:required] && !is_property_present?(property_name)
|
|
|
|
next if !has_valid_property_value_type?(property_attributes, property_name)
|
|
|
|
next if !has_valid_property_value?(property_attributes, property_name)
|
2024-02-19 13:19:35 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-02-20 09:17:27 +08:00
|
|
|
def has_valid_property_value_type?(property_attributes, property_name)
|
2024-02-19 13:19:35 +08:00
|
|
|
value = @object[property_name]
|
|
|
|
type = property_attributes[:type]
|
|
|
|
|
2024-02-20 09:17:27 +08:00
|
|
|
return true if (value.nil? && type != "enum")
|
2024-02-19 13:19:35 +08:00
|
|
|
|
|
|
|
is_value_valid =
|
|
|
|
case type
|
|
|
|
when "string"
|
|
|
|
value.is_a?(String)
|
2024-02-21 08:11:15 +08:00
|
|
|
when "integer", "category"
|
2024-02-19 13:19:35 +08:00
|
|
|
value.is_a?(Integer)
|
|
|
|
when "float"
|
|
|
|
value.is_a?(Float) || value.is_a?(Integer)
|
|
|
|
when "boolean"
|
|
|
|
[true, false].include?(value)
|
|
|
|
when "enum"
|
|
|
|
property_attributes[:choices].include?(value)
|
|
|
|
else
|
|
|
|
add_error(property_name, I18n.t("themes.settings_errors.objects.invalid_type", type:))
|
2024-02-20 09:17:27 +08:00
|
|
|
return false
|
2024-02-16 09:35:16 +08:00
|
|
|
end
|
2024-02-19 13:19:35 +08:00
|
|
|
|
2024-02-20 09:17:27 +08:00
|
|
|
if is_value_valid
|
|
|
|
true
|
|
|
|
else
|
2024-02-19 13:19:35 +08:00
|
|
|
add_error(
|
|
|
|
property_name,
|
|
|
|
I18n.t("themes.settings_errors.objects.not_valid_#{type}_value", property_attributes),
|
|
|
|
)
|
2024-02-20 09:17:27 +08:00
|
|
|
false
|
2024-02-16 09:35:16 +08:00
|
|
|
end
|
|
|
|
end
|
2024-02-19 13:19:35 +08:00
|
|
|
|
2024-02-20 09:17:27 +08:00
|
|
|
def has_valid_property_value?(property_attributes, property_name)
|
|
|
|
validations = property_attributes[:validations]
|
|
|
|
type = property_attributes[:type]
|
|
|
|
value = @object[property_name]
|
|
|
|
|
|
|
|
case type
|
2024-02-21 08:11:15 +08:00
|
|
|
when "category"
|
|
|
|
if !valid_category_ids.include?(value)
|
|
|
|
add_error(property_name, I18n.t("themes.settings_errors.objects.not_valid_category_value"))
|
|
|
|
return false
|
|
|
|
end
|
2024-02-20 09:17:27 +08:00
|
|
|
when "string"
|
2024-02-21 08:11:15 +08:00
|
|
|
if (min = validations&.dig(:min_length)) && value.length < min
|
2024-02-20 09:17:27 +08:00
|
|
|
add_error(
|
|
|
|
property_name,
|
2024-02-21 08:11:15 +08:00
|
|
|
I18n.t("themes.settings_errors.objects.string_value_not_valid_min", min:),
|
2024-02-20 09:17:27 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
2024-02-21 08:11:15 +08:00
|
|
|
if (max = validations&.dig(:max_length)) && value.length > max
|
2024-02-20 09:17:27 +08:00
|
|
|
add_error(
|
|
|
|
property_name,
|
2024-02-21 08:11:15 +08:00
|
|
|
I18n.t("themes.settings_errors.objects.string_value_not_valid_max", max: max),
|
2024-02-20 09:17:27 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
2024-02-21 08:11:15 +08:00
|
|
|
if validations&.dig(:url) && !value.match?(URI.regexp)
|
2024-02-20 09:17:27 +08:00
|
|
|
add_error(
|
|
|
|
property_name,
|
|
|
|
I18n.t("themes.settings_errors.objects.string_value_not_valid_url"),
|
|
|
|
)
|
|
|
|
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
when "integer", "float"
|
2024-02-21 08:11:15 +08:00
|
|
|
if (min = validations&.dig(:min)) && value < min
|
2024-02-20 09:17:27 +08:00
|
|
|
add_error(
|
|
|
|
property_name,
|
2024-02-21 08:11:15 +08:00
|
|
|
I18n.t("themes.settings_errors.objects.number_value_not_valid_min", min:),
|
2024-02-20 09:17:27 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
2024-02-21 08:11:15 +08:00
|
|
|
if (max = validations&.dig(:max)) && value > max
|
2024-02-20 09:17:27 +08:00
|
|
|
add_error(
|
|
|
|
property_name,
|
2024-02-21 08:11:15 +08:00
|
|
|
I18n.t("themes.settings_errors.objects.number_value_not_valid_max", max:),
|
2024-02-20 09:17:27 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
|
|
|
def is_property_present?(property_name)
|
2024-02-19 13:19:35 +08:00
|
|
|
if @object[property_name].nil?
|
|
|
|
add_error(property_name, I18n.t("themes.settings_errors.objects.required"))
|
|
|
|
false
|
2024-02-20 09:17:27 +08:00
|
|
|
else
|
|
|
|
true
|
2024-02-19 13:19:35 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def add_error(property_name, error)
|
|
|
|
@errors[property_name] ||= []
|
|
|
|
@errors[property_name] << error
|
|
|
|
end
|
2024-02-21 08:11:15 +08:00
|
|
|
|
|
|
|
def valid_category_ids
|
|
|
|
@valid_category_ids ||=
|
|
|
|
Set.new(
|
|
|
|
Category.where(id: fetch_property_values_of_type(@properties, @object, "category")).pluck(
|
|
|
|
:id,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
def fetch_property_values_of_type(properties, object, type)
|
|
|
|
values = Set.new
|
|
|
|
|
|
|
|
properties.each do |property_name, property_attributes|
|
|
|
|
if property_attributes[:type] == type
|
|
|
|
values << object[property_name]
|
|
|
|
elsif property_attributes[:type] == "objects"
|
|
|
|
object[property_name]&.each do |child_object|
|
|
|
|
values.merge(
|
|
|
|
fetch_property_values_of_type(
|
|
|
|
property_attributes[:schema][:properties],
|
|
|
|
child_object,
|
|
|
|
type,
|
|
|
|
),
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
values
|
|
|
|
end
|
2024-02-16 09:35:16 +08:00
|
|
|
end
|