Spiegel von
https://github.com/paviliondev/discourse-custom-wizard.git
synchronisiert 2024-11-08 19:38:00 +01:00
213 Zeilen
5,4 KiB
Ruby
213 Zeilen
5,4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class CustomWizard::Template
|
|
include HasErrors
|
|
|
|
AFTER_SIGNUP_CACHE_KEY ||= "after_signup_wizard_ids"
|
|
AFTER_TIME_CACHE_KEY ||= "after_time_wizard_ids"
|
|
|
|
attr_reader :data,
|
|
:opts,
|
|
:steps,
|
|
:actions
|
|
|
|
def initialize(data)
|
|
@data = data
|
|
@steps = data['steps'] || []
|
|
@actions = data['actions'] || []
|
|
end
|
|
|
|
def save(opts = {})
|
|
@opts = opts
|
|
|
|
normalize_data
|
|
validate_data
|
|
prepare_data
|
|
return false if errors.any?
|
|
|
|
ActiveRecord::Base.transaction do
|
|
schedule_save_jobs unless opts[:skip_jobs]
|
|
PluginStore.set(CustomWizard::PLUGIN_NAME, @data[:id], @data)
|
|
ensure_wizard_upload_references!
|
|
end
|
|
|
|
self.class.clear_cache_keys
|
|
|
|
@data[:id]
|
|
end
|
|
|
|
def self.save(data, opts = {})
|
|
new(data).save(opts)
|
|
end
|
|
|
|
def self.create(wizard_id)
|
|
if data = find(wizard_id)
|
|
new(data)
|
|
else
|
|
nil
|
|
end
|
|
end
|
|
|
|
def self.find(wizard_id)
|
|
PluginStore.get(CustomWizard::PLUGIN_NAME, wizard_id)
|
|
end
|
|
|
|
def self.find_record(wizard_id)
|
|
PluginStoreRow.find_by(plugin_name: CustomWizard::PLUGIN_NAME, key: wizard_id)
|
|
end
|
|
|
|
def self.remove(wizard_id)
|
|
wizard = CustomWizard::Wizard.create(wizard_id)
|
|
return false if !wizard
|
|
|
|
ActiveRecord::Base.transaction do
|
|
ensure_wizard_upload_references!(wizard_id)
|
|
PluginStore.remove(CustomWizard::PLUGIN_NAME, wizard.id)
|
|
clear_user_wizard_redirect(wizard_id, after_time: !!wizard.after_time)
|
|
related_custom_fields = CategoryCustomField.where(name: 'create_topic_wizard', value: wizard.name.parameterize(separator: "_"))
|
|
related_custom_fields.destroy_all
|
|
end
|
|
|
|
clear_cache_keys
|
|
|
|
true
|
|
end
|
|
|
|
def self.exists?(wizard_id)
|
|
PluginStoreRow.exists?(plugin_name: 'custom_wizard', key: wizard_id)
|
|
end
|
|
|
|
def self.list(setting: nil, query_str: nil, order: :id)
|
|
query = "plugin_name = 'custom_wizard'"
|
|
query += " AND (value::json ->> '#{setting}')::boolean IS TRUE" if setting
|
|
query += " #{query_str}" if query_str
|
|
|
|
PluginStoreRow.where(query).order(order)
|
|
.reduce([]) do |result, record|
|
|
attrs = JSON.parse(record.value)
|
|
|
|
if attrs.present? &&
|
|
attrs.is_a?(Hash) &&
|
|
attrs['id'].present? &&
|
|
attrs['name'].present?
|
|
|
|
result.push(attrs)
|
|
end
|
|
|
|
result
|
|
end
|
|
end
|
|
|
|
def self.clear_user_wizard_redirect(wizard_id, after_time: false)
|
|
UserCustomField.where(name: 'redirect_to_wizard', value: wizard_id).destroy_all
|
|
|
|
if after_time
|
|
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: wizard_id)
|
|
end
|
|
end
|
|
|
|
def self.after_signup_ids
|
|
::CustomWizard::Cache.wrap(AFTER_SIGNUP_CACHE_KEY) do
|
|
list(setting: 'after_signup').map { |t| t['id'] }
|
|
end
|
|
end
|
|
|
|
def self.after_time_ids
|
|
::CustomWizard::Cache.wrap(AFTER_TIME_CACHE_KEY) do
|
|
list(
|
|
setting: 'after_time',
|
|
query_str: "AND (value::json ->> 'after_time_scheduled')::timestamp < CURRENT_TIMESTAMP"
|
|
).map { |t| t['id'] }
|
|
end
|
|
end
|
|
|
|
def self.can_redirect_users?(wizard_id)
|
|
after_signup_ids.include?(wizard_id) || after_time_ids.include?(wizard_id)
|
|
end
|
|
|
|
def self.clear_cache_keys
|
|
CustomWizard::Cache.new(AFTER_SIGNUP_CACHE_KEY).delete
|
|
CustomWizard::Cache.new(AFTER_TIME_CACHE_KEY).delete
|
|
end
|
|
|
|
def self.ensure_wizard_upload_references!(wizard_id, wizard_upload_ids = [])
|
|
wizard_record = find_record(wizard_id)
|
|
|
|
if wizard_record
|
|
UploadReference.ensure_exist!(
|
|
upload_ids: wizard_upload_ids,
|
|
target_type: "PluginStoreRow",
|
|
target_id: wizard_record.id
|
|
)
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def normalize_data
|
|
@data = ::JSON.parse(@data) if @data.is_a?(String)
|
|
@data = @data.with_indifferent_access
|
|
end
|
|
|
|
def prepare_data
|
|
@data[:steps].each do |step|
|
|
if step[:raw_description]
|
|
step[:description] = step[:raw_description]
|
|
end
|
|
|
|
remove_non_mapped_index(step)
|
|
|
|
step[:fields].each do |field|
|
|
remove_non_mapped_index(field)
|
|
end
|
|
end
|
|
end
|
|
|
|
def validate_data
|
|
validator = CustomWizard::TemplateValidator.new(@data, @opts)
|
|
validator.perform
|
|
add_errors_from(validator)
|
|
end
|
|
|
|
def schedule_save_jobs
|
|
if @data[:after_time] && @data[:after_time_scheduled]
|
|
wizard_id = @data[:id]
|
|
old_data = CustomWizard::Template.find(data[:id])
|
|
|
|
begin
|
|
enqueue_wizard_at = Time.parse(@data[:after_time_scheduled]).utc
|
|
rescue ArgumentError
|
|
errors.add :validation, I18n.t("wizard.validation.after_time")
|
|
raise ActiveRecord::Rollback.new
|
|
end
|
|
|
|
if enqueue_wizard_at
|
|
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: wizard_id)
|
|
Jobs.enqueue_at(enqueue_wizard_at, :set_after_time_wizard, wizard_id: wizard_id)
|
|
elsif old_data && old_data[:after_time]
|
|
clear_user_wizard_redirect(wizard_id, after_time: true)
|
|
end
|
|
end
|
|
end
|
|
|
|
def remove_non_mapped_index(object)
|
|
if !object[:index].is_a?(Array)
|
|
object.delete(:index)
|
|
end
|
|
end
|
|
|
|
def ensure_wizard_upload_references!
|
|
upload_ids = []
|
|
|
|
@data[:steps].each do |step|
|
|
upload_ids << step[:banner_upload_id] if step[:banner_upload_id]
|
|
|
|
step[:fields].each do |field|
|
|
upload_ids << field[:image_upload_id] if field[:image_upload_id]
|
|
end
|
|
end
|
|
|
|
upload_ids = upload_ids.select { |upload_id| Upload.exists?(upload_id) }
|
|
self.class.ensure_wizard_upload_references!(@data[:id], upload_ids)
|
|
end
|
|
end
|