# frozen_string_literal: true module DiscourseAutomation class Field < ActiveRecord::Base self.table_name = "discourse_automation_fields" belongs_to :automation, class_name: "DiscourseAutomation::Automation" around_save :on_update_callback def on_update_callback previous_fields = automation.serialized_fields automation.reset! yield automation&.triggerable&.on_update&.call( automation, automation.serialized_fields, previous_fields, ) end validate :required_field def required_field if template && template[:required] && metadata && metadata["value"].blank? raise_required_field(name, target, targetable) end end validate :validator def validator if template && template[:validator] error = template[:validator].call(metadata["value"]) errors.add(:base, error) if error end end def targetable target == "trigger" ? automation.triggerable : automation.scriptable end def template targetable&.fields&.find do |tf| targetable.id == target && tf[:name].to_s == name && tf[:component].to_s == component end end validate :metadata_schema def metadata_schema if !(targetable.components.include?(component.to_sym)) errors.add( :base, I18n.t( "discourse_automation.models.fields.invalid_field", component: component, target: target, target_name: targetable.name, ), ) else schema = SCHEMAS[component] if !schema || !JSONSchemer.schema({ "type" => "object", "properties" => schema }).valid?(metadata) errors.add( :base, I18n.t( "discourse_automation.models.fields.invalid_metadata", component: component, field: name, ), ) end end end SCHEMAS = { "key-value" => { "type" => "array", "uniqueItems" => true, "items" => { "type" => "object", "title" => "group", "properties" => { "key" => { "type" => "string", }, "value" => { "type" => "string", }, }, }, }, "choices" => { "value" => { "type" => %w[string integer null], }, }, "tags" => { "value" => { "type" => "array", "items" => [{ type: "string" }], }, }, "trust-levels" => { "value" => { "type" => "array", "items" => [{ type: "integer" }], }, }, "categories" => { "value" => { "type" => "array", "items" => [{ type: "string" }], }, }, "category" => { "value" => { "type" => %w[string integer null], }, }, "category_notification_level" => { "value" => { "type" => "integer", }, }, "custom_field" => { "value" => { "type" => "integer", }, }, "custom_fields" => { "value" => { "type" => [{ type: "string" }], }, }, "user" => { "value" => { "type" => "string", }, }, "user_profile" => { "value" => { "type" => "array", "items" => [{ type: "string" }], }, }, "users" => { "value" => { "type" => "array", "items" => [{ type: "string" }], }, }, "text" => { "value" => { "type" => %w[string integer null], }, }, "post" => { "value" => { "type" => %w[string integer null], }, }, "message" => { "value" => { "type" => %w[string integer null], }, }, "boolean" => { "value" => { "type" => ["boolean"], }, }, "text_list" => { "value" => { "type" => "array", "items" => [{ type: "string" }], }, }, "date_time" => { "value" => { "type" => "string", }, }, "group" => { "value" => { "type" => "integer", }, }, "email_group_user" => { "value" => { "type" => "array", "items" => [{ type: "string" }], }, }, "pms" => { type: "array", items: [ { type: "object", properties: { "raw" => { "type" => "string", }, "title" => { "type" => "string", }, "delay" => { "type" => "integer", }, "prefers_encrypt" => { "type" => "boolean", }, }, }, ], }, "period" => { "type" => "object", "properties" => { "interval" => { "type" => "integer", }, "frequency" => { "type" => "string", }, }, }, } private def raise_required_field(name, target, targetable) errors.add( :base, I18n.t( "discourse_automation.models.fields.required_field", name: name, target: target, target_name: targetable.name, ), ) end end end