mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 04:31:10 +08:00
FEATURE: support a description attribute on form template fields (#23744)
* FEATURE: support a description attribute on form template fields
This commit is contained in:
@ -3,62 +3,72 @@
|
||||
class FormTemplateYamlValidator < ActiveModel::Validator
|
||||
RESERVED_KEYWORDS = %w[title body category category_id tags]
|
||||
ALLOWED_TYPES = %w[checkbox dropdown input multi-select textarea upload]
|
||||
HTML_SANITIZATION_OPTIONS = { elements: ["a"], attributes: { "a" => %w[href target] } }
|
||||
|
||||
def validate(record)
|
||||
begin
|
||||
yaml = Psych.safe_load(record.template)
|
||||
check_missing_fields(record, yaml)
|
||||
check_allowed_types(record, yaml)
|
||||
check_ids(record, yaml)
|
||||
|
||||
unless yaml.is_a?(Array)
|
||||
record.errors.add(:template, I18n.t("form_templates.errors.invalid_yaml"))
|
||||
return
|
||||
end
|
||||
|
||||
existing_ids = []
|
||||
yaml.each do |field|
|
||||
check_missing_fields(record, field)
|
||||
check_allowed_types(record, field)
|
||||
check_ids(record, field, existing_ids)
|
||||
check_descriptions_html(record, field)
|
||||
end
|
||||
rescue Psych::SyntaxError
|
||||
record.errors.add(:template, I18n.t("form_templates.errors.invalid_yaml"))
|
||||
end
|
||||
end
|
||||
|
||||
def check_allowed_types(record, yaml)
|
||||
yaml.each do |field|
|
||||
if !ALLOWED_TYPES.include?(field["type"])
|
||||
return(
|
||||
record.errors.add(
|
||||
:template,
|
||||
I18n.t(
|
||||
"form_templates.errors.invalid_type",
|
||||
type: field["type"],
|
||||
valid_types: ALLOWED_TYPES.join(", "),
|
||||
),
|
||||
)
|
||||
)
|
||||
end
|
||||
def check_allowed_types(record, field)
|
||||
if !ALLOWED_TYPES.include?(field["type"])
|
||||
record.errors.add(
|
||||
:template,
|
||||
I18n.t(
|
||||
"form_templates.errors.invalid_type",
|
||||
type: field["type"],
|
||||
valid_types: ALLOWED_TYPES.join(", "),
|
||||
),
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def check_missing_fields(record, yaml)
|
||||
yaml.each do |field|
|
||||
if field["type"].blank?
|
||||
return(record.errors.add(:template, I18n.t("form_templates.errors.missing_type")))
|
||||
end
|
||||
if field["id"].blank?
|
||||
return(record.errors.add(:template, I18n.t("form_templates.errors.missing_id")))
|
||||
end
|
||||
def check_missing_fields(record, field)
|
||||
if field["type"].blank?
|
||||
record.errors.add(:template, I18n.t("form_templates.errors.missing_type"))
|
||||
end
|
||||
record.errors.add(:template, I18n.t("form_templates.errors.missing_id")) if field["id"].blank?
|
||||
end
|
||||
|
||||
def check_descriptions_html(record, field)
|
||||
description = field.dig("attributes", "description")
|
||||
|
||||
return if description.blank?
|
||||
|
||||
sanitized_html = Sanitize.fragment(description, HTML_SANITIZATION_OPTIONS)
|
||||
|
||||
is_safe_html = sanitized_html == Loofah.html5_fragment(description).to_s
|
||||
|
||||
unless is_safe_html
|
||||
record.errors.add(:template, I18n.t("form_templates.errors.unsafe_description"))
|
||||
end
|
||||
end
|
||||
|
||||
def check_ids(record, yaml)
|
||||
ids = []
|
||||
yaml.each do |field|
|
||||
next if field["id"].blank?
|
||||
|
||||
if RESERVED_KEYWORDS.include?(field["id"])
|
||||
return(
|
||||
record.errors.add(:template, I18n.t("form_templates.errors.reserved_id", id: field["id"]))
|
||||
)
|
||||
end
|
||||
|
||||
if ids.include?(field["id"])
|
||||
return(record.errors.add(:template, I18n.t("form_templates.errors.duplicate_ids")))
|
||||
end
|
||||
|
||||
ids << field["id"]
|
||||
def check_ids(record, field, existing_ids)
|
||||
if RESERVED_KEYWORDS.include?(field["id"])
|
||||
record.errors.add(:template, I18n.t("form_templates.errors.reserved_id", id: field["id"]))
|
||||
end
|
||||
|
||||
if existing_ids.include?(field["id"])
|
||||
record.errors.add(:template, I18n.t("form_templates.errors.duplicate_ids"))
|
||||
end
|
||||
|
||||
existing_ids << field["id"] unless field["id"].blank?
|
||||
end
|
||||
end
|
||||
|
Reference in New Issue
Block a user