mirror of
https://github.com/discourse/discourse.git
synced 2026-08-10 04:58:31 -05:00
DEV: Validate default value for type: objects theme settings (#25833)
Why this change? This change adds validation for the default value for `type: objects` theme settings when a setting theme field is uploaded. This helps the theme author to ensure that the objects which they specifc in the default value adhere to the schema which they have declared. When an error is encountered in one of the objects, the error message will look something like: `"The property at JSON Pointer '/0/title' must be at least 5 characters long."` We use a JSON Pointer to reference the property in the object which is something most json-schema validator uses as well. What does this change do? 1. This commit once again changes the shape of hash returned by `ThemeSettingsObjectValidator.validate`. Instead of using the property name as the key previously, we have decided to avoid multiple levels of nesting and instead use a JSON Pointer as the key which helps to simplify the implementation. 2 Introduces `ThemeSettingsObjectValidator.validate_objects` which returns an array of validation error messages for all the objects passed to the method.
This commit is contained in:
@@ -1,37 +1,72 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ThemeSettingsObjectValidator
|
||||
class << self
|
||||
def validate_objects(schema:, objects:)
|
||||
error_messages = []
|
||||
|
||||
objects.each_with_index do |object, index|
|
||||
humanize_error_messages(
|
||||
self.new(schema: schema, object: object).validate,
|
||||
index:,
|
||||
error_messages:,
|
||||
)
|
||||
end
|
||||
|
||||
error_messages
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def humanize_error_messages(errors, index:, error_messages:)
|
||||
errors.each do |property_json_pointer, error_details|
|
||||
error_messages.push(*error_details.humanize_messages("/#{index}#{property_json_pointer}"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ThemeSettingsObjectErrors
|
||||
def initialize
|
||||
@errors = []
|
||||
end
|
||||
|
||||
def add_error(key, i18n_opts = {})
|
||||
@errors << ThemeSettingsObjectError.new(key, i18n_opts)
|
||||
def add_error(error, i18n_opts = {})
|
||||
@errors << ThemeSettingsObjectError.new(error, i18n_opts)
|
||||
end
|
||||
|
||||
def humanize_messages(property_json_pointer)
|
||||
@errors.map { |error| error.humanize_messages(property_json_pointer) }
|
||||
end
|
||||
|
||||
def full_messages
|
||||
@errors.map(&:error_message)
|
||||
end
|
||||
end
|
||||
|
||||
class ThemeSettingsObjectError
|
||||
def initialize(key, i18n_opts = {})
|
||||
@key = key
|
||||
def initialize(error, i18n_opts = {})
|
||||
@error = error
|
||||
@i18n_opts = i18n_opts
|
||||
end
|
||||
|
||||
def humanize_messages(property_json_pointer)
|
||||
I18n.t(
|
||||
"themes.settings_errors.objects.humanize_#{@error}",
|
||||
@i18n_opts.merge(property_json_pointer:),
|
||||
)
|
||||
end
|
||||
|
||||
def error_message
|
||||
I18n.t("themes.settings_errors.objects.#{@key}", @i18n_opts)
|
||||
I18n.t("themes.settings_errors.objects.#{@error}", @i18n_opts)
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(schema:, object:, valid_category_ids: nil)
|
||||
def initialize(schema:, object:, valid_category_ids: nil, json_pointer_prefix: "", errors: {})
|
||||
@object = object
|
||||
@schema_name = schema[:name]
|
||||
@properties = schema[:properties]
|
||||
@errors = {}
|
||||
@errors = errors
|
||||
@valid_category_ids = valid_category_ids
|
||||
@json_pointer_prefix = json_pointer_prefix
|
||||
end
|
||||
|
||||
def validate
|
||||
@@ -39,15 +74,17 @@ class ThemeSettingsObjectValidator
|
||||
|
||||
@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(
|
||||
self
|
||||
.class
|
||||
.new(schema: property_attributes[:schema], object: child_object, valid_category_ids:)
|
||||
.validate,
|
||||
)
|
||||
@object[property_name]&.each_with_index do |child_object, index|
|
||||
self
|
||||
.class
|
||||
.new(
|
||||
schema: property_attributes[:schema],
|
||||
object: child_object,
|
||||
valid_category_ids:,
|
||||
json_pointer_prefix: "#{@json_pointer_prefix}#{property_name}/#{index}/",
|
||||
errors: @errors,
|
||||
)
|
||||
.validate
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -148,8 +185,13 @@ class ThemeSettingsObjectValidator
|
||||
end
|
||||
|
||||
def add_error(property_name, key, i18n_opts = {})
|
||||
@errors[property_name] ||= ThemeSettingsObjectErrors.new
|
||||
@errors[property_name].add_error(key, i18n_opts)
|
||||
pointer = json_pointer(property_name)
|
||||
@errors[pointer] ||= ThemeSettingsObjectErrors.new
|
||||
@errors[pointer].add_error(key, i18n_opts)
|
||||
end
|
||||
|
||||
def json_pointer(property_name)
|
||||
"/#{@json_pointer_prefix}#{property_name}"
|
||||
end
|
||||
|
||||
def valid_category_ids
|
||||
|
||||
@@ -51,6 +51,10 @@ class ThemeSettingsValidator
|
||||
errors:,
|
||||
translation_prefix: "string",
|
||||
)
|
||||
when types[:objects]
|
||||
errors.push(
|
||||
ThemeSettingsObjectValidator.validate_objects(schema: opts[:schema], objects: value),
|
||||
)
|
||||
end
|
||||
|
||||
errors
|
||||
|
||||
Reference in New Issue
Block a user