DEV: Support validations options for string and numeral types (#25719)

Why this change?

This commit updates `ThemeSettingsObjectValidator` to validate a
property's value against the validations listed in the schema.

For string types, `min_length`, `max_length` and `url` are supported.
For integer and float types, `min` and `max` are supported.
This commit is contained in:
Alan Guo Xiang Tan 2024-02-20 09:17:27 +08:00 committed by GitHub
parent 3894ee6cb6
commit bf3c4b634a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 217 additions and 10 deletions

View File

@ -142,6 +142,11 @@ en:
not_valid_float_value: "must be a float" not_valid_float_value: "must be a float"
not_valid_boolean_value: "must be a boolean" not_valid_boolean_value: "must be a boolean"
not_valid_enum_value: "must be one of the following: %{choices}" not_valid_enum_value: "must be one of the following: %{choices}"
string_value_not_valid_min: "must be at least %{min} characters long"
string_value_not_valid_max: "must be at most %{max} characters long"
number_value_not_valid_min: "must be larger than or equal to %{min}"
number_value_not_valid_max: "must be smaller than or equal to %{max}"
string_value_not_valid_url: "must be a valid URL"
locale_errors: locale_errors:
top_level_locale: "The top level key in a locale file must match the locale name" top_level_locale: "The top level key in a locale file must match the locale name"
invalid_yaml: "Translation YAML invalid" invalid_yaml: "Translation YAML invalid"

View File

@ -30,17 +30,18 @@ class ThemeSettingsObjectValidator
def validate_properties def validate_properties
@properties.each do |property_name, property_attributes| @properties.each do |property_name, property_attributes|
next if property_attributes[:required] && validate_required_property(property_name) next if property_attributes[:required] && !is_property_present?(property_name)
validate_property_type(property_attributes, property_name) next if !has_valid_property_value_type?(property_attributes, property_name)
next if !has_valid_property_value?(property_attributes, property_name)
end end
end end
def validate_property_type(property_attributes, property_name) def has_valid_property_value_type?(property_attributes, property_name)
value = @object[property_name] value = @object[property_name]
type = property_attributes[:type] type = property_attributes[:type]
return if (value.nil? && type != "enum") return true if (value.nil? && type != "enum")
return if type == "objects" return true if type == "objects"
is_value_valid = is_value_valid =
case type case type
@ -56,23 +57,97 @@ class ThemeSettingsObjectValidator
property_attributes[:choices].include?(value) property_attributes[:choices].include?(value)
else else
add_error(property_name, I18n.t("themes.settings_errors.objects.invalid_type", type:)) add_error(property_name, I18n.t("themes.settings_errors.objects.invalid_type", type:))
return return false
end end
if !is_value_valid if is_value_valid
true
else
add_error( add_error(
property_name, property_name,
I18n.t("themes.settings_errors.objects.not_valid_#{type}_value", property_attributes), I18n.t("themes.settings_errors.objects.not_valid_#{type}_value", property_attributes),
) )
false
end end
end end
def validate_required_property(property_name) def has_valid_property_value?(property_attributes, property_name)
validations = property_attributes[:validations]
return true if validations.blank?
type = property_attributes[:type]
value = @object[property_name]
case type
when "string"
if validations[:min_length] && value.length < validations[:min_length]
add_error(
property_name,
I18n.t(
"themes.settings_errors.objects.string_value_not_valid_min",
min: validations[:min_length],
),
)
return false
end
if validations[:max_length] && value.length > validations[:max_length]
add_error(
property_name,
I18n.t(
"themes.settings_errors.objects.string_value_not_valid_max",
max: validations[:max_length],
),
)
return false
end
if validations[:url] && !value.match?(URI.regexp)
add_error(
property_name,
I18n.t("themes.settings_errors.objects.string_value_not_valid_url"),
)
return false
end
when "integer", "float"
if validations[:min] && value < validations[:min]
add_error(
property_name,
I18n.t(
"themes.settings_errors.objects.number_value_not_valid_min",
min: validations[:min],
),
)
return false
end
if validations[:max] && value > validations[:max]
add_error(
property_name,
I18n.t(
"themes.settings_errors.objects.number_value_not_valid_max",
max: validations[:max],
),
)
return false
end
end
true
end
def is_property_present?(property_name)
if @object[property_name].nil? if @object[property_name].nil?
add_error(property_name, I18n.t("themes.settings_errors.objects.required")) add_error(property_name, I18n.t("themes.settings_errors.objects.required"))
true
else
false false
else
true
end end
end end

View File

@ -139,6 +139,29 @@ RSpec.describe ThemeSettingsObjectValidator do
described_class.new(schema: schema, object: { float_property: "string" }).validate, described_class.new(schema: schema, object: { float_property: "string" }).validate,
).to eq(float_property: ["must be a float"]) ).to eq(float_property: ["must be a float"])
end end
it "should return the right hash of error messages when integer property does not satisfy min or max validations" do
schema = {
name: "section",
properties: {
float_property: {
type: "float",
validations: {
min: 5.5,
max: 11.5,
},
},
},
}
expect(described_class.new(schema: schema, object: { float_property: 4.5 }).validate).to eq(
float_property: ["must be larger than or equal to 5.5"],
)
expect(
described_class.new(schema: schema, object: { float_property: 12.5 }).validate,
).to eq(float_property: ["must be smaller than or equal to 11.5"])
end
end end
context "for integer properties" do context "for integer properties" do
@ -159,6 +182,48 @@ RSpec.describe ThemeSettingsObjectValidator do
described_class.new(schema: schema, object: { integer_property: 1.0 }).validate, described_class.new(schema: schema, object: { integer_property: 1.0 }).validate,
).to eq(integer_property: ["must be an integer"]) ).to eq(integer_property: ["must be an integer"])
end end
it "should not return any error messages when the value of the integer property satisfies min and max validations" do
schema = {
name: "section",
properties: {
integer_property: {
type: "integer",
validations: {
min: 5,
max: 10,
},
},
},
}
expect(described_class.new(schema: schema, object: { integer_property: 6 }).validate).to eq(
{},
)
end
it "should return the right hash of error messages when integer property does not satisfy min or max validations" do
schema = {
name: "section",
properties: {
integer_property: {
type: "integer",
validations: {
min: 5,
max: 10,
},
},
},
}
expect(described_class.new(schema: schema, object: { integer_property: 4 }).validate).to eq(
integer_property: ["must be larger than or equal to 5"],
)
expect(
described_class.new(schema: schema, object: { integer_property: 11 }).validate,
).to eq(integer_property: ["must be smaller than or equal to 10"])
end
end end
context "for string properties" do context "for string properties" do
@ -171,10 +236,72 @@ RSpec.describe ThemeSettingsObjectValidator do
end end
it "should return the right hash of error messages when value of property is not of type string" do it "should return the right hash of error messages when value of property is not of type string" do
schema = { name: "section", properties: { string_property: { type: "string" } } }
expect(described_class.new(schema: schema, object: { string_property: 1 }).validate).to eq( expect(described_class.new(schema: schema, object: { string_property: 1 }).validate).to eq(
string_property: ["must be a string"], string_property: ["must be a string"],
) )
end end
it "should return the right hash of error messages when string property does not statisfy url validation" do
schema = {
name: "section",
properties: {
string_property: {
type: "string",
validations: {
url: true,
},
},
},
}
expect(
described_class.new(schema: schema, object: { string_property: "not a url" }).validate,
).to eq(string_property: ["must be a valid URL"])
end
it "should not return any error messages when the value of the string property satisfies min_length and max_length validations" do
schema = {
name: "section",
properties: {
string_property: {
type: "string",
validations: {
min_length: 5,
max_length: 10,
},
},
},
}
expect(
described_class.new(schema: schema, object: { string_property: "123456" }).validate,
).to eq({})
end
it "should return the right hash of error messages when string property does not satisfy min_length or max_length validations" do
schema = {
name: "section",
properties: {
string_property: {
type: "string",
validations: {
min_length: 5,
max_length: 10,
},
},
},
}
expect(
described_class.new(schema: schema, object: { string_property: "1234" }).validate,
).to eq(string_property: ["must be at least 5 characters long"])
expect(
described_class.new(schema: schema, object: { string_property: "12345678910" }).validate,
).to eq(string_property: ["must be at most 10 characters long"])
end
end end
end end
end end