Spiegel von
https://github.com/paviliondev/discourse-custom-wizard.git
synchronisiert 2024-11-24 18:30:27 +01:00
799 Zeilen
21 KiB
Ruby
799 Zeilen
21 KiB
Ruby
# frozen_string_literal: true
|
|
class CustomWizard::Action
|
|
attr_accessor :submission, :action, :user, :guardian, :result
|
|
|
|
REQUIRES_USER = %w[update_profile open_composer watch_categories add_to_group]
|
|
|
|
WIZARD_USER = "wizard-user"
|
|
|
|
def initialize(opts)
|
|
@wizard = opts[:wizard]
|
|
@action = opts[:action]
|
|
@user = @wizard.user
|
|
@guardian = Guardian.new(@user)
|
|
@submission = opts[:submission]
|
|
@log = []
|
|
@result = CustomWizard::ActionResult.new
|
|
end
|
|
|
|
def perform
|
|
if REQUIRES_USER.include?(action["id"]) && !@user
|
|
log_error("action requires user", "id: #{action["id"]};")
|
|
@result.success = false
|
|
return @result
|
|
end
|
|
|
|
ActiveRecord::Base.transaction { self.send(action["type"].to_sym) }
|
|
|
|
@result.handler.enqueue_jobs if creates_post? && @result.success?
|
|
|
|
@submission.fields[action["id"]] = @result.output if @result.success? && @result.output.present?
|
|
|
|
save_log
|
|
|
|
@result.submission = @submission
|
|
@result
|
|
end
|
|
|
|
def mapper_data
|
|
@mapper_data ||= @submission&.fields_and_meta || {}
|
|
end
|
|
|
|
def mapper
|
|
@mapper ||= CustomWizard::Mapper.new(user: user, data: mapper_data)
|
|
end
|
|
|
|
def callbacks_for(action)
|
|
self.class.callbacks[action] || []
|
|
end
|
|
|
|
def create_topic
|
|
params = basic_topic_params.merge(public_topic_params)
|
|
|
|
callbacks_for(:before_create_topic).each do |acb|
|
|
params = acb.call(params, @wizard, @action, @submission)
|
|
end
|
|
|
|
if params[:title].present? && params[:raw].present?
|
|
creator = PostCreator.new(topic_poster, params)
|
|
post = creator.create
|
|
|
|
if creator.errors.present?
|
|
messages = creator.errors.full_messages.join(" ")
|
|
log_error("failed to create", messages)
|
|
elsif action["skip_redirect"].blank?
|
|
@submission.redirect_on_complete = post.topic.url
|
|
end
|
|
|
|
if creator.errors.blank?
|
|
log_success("created topic", "id: #{post.topic.id}")
|
|
result.handler = creator
|
|
result.output = post.topic.id
|
|
end
|
|
else
|
|
log_error("invalid topic params", "title: #{params[:title]}; post: #{params[:raw]}")
|
|
end
|
|
end
|
|
|
|
def send_message
|
|
if action["required"].present?
|
|
required =
|
|
CustomWizard::Mapper.new(inputs: action["required"], data: mapper_data, user: user).perform
|
|
|
|
if required.blank?
|
|
log_error("required input not present")
|
|
return
|
|
end
|
|
end
|
|
|
|
params = basic_topic_params
|
|
|
|
targets =
|
|
CustomWizard::Mapper.new(
|
|
inputs: action["recipient"],
|
|
data: mapper_data,
|
|
user: user,
|
|
multiple: true,
|
|
).perform
|
|
|
|
if targets.blank?
|
|
log_error("no recipients", "send_message has no recipients")
|
|
return
|
|
end
|
|
|
|
params[:target_group_names] = []
|
|
params[:target_usernames] = []
|
|
params[:target_emails] = []
|
|
[*targets].each do |target|
|
|
if Group.find_by(name: target)
|
|
params[:target_group_names] << target
|
|
elsif User.find_by_username(target)
|
|
params[:target_usernames] << target
|
|
elsif target.match(/@/) # Compare discourse/discourse/app/controllers/posts_controller.rb#L922-L923
|
|
params[:target_emails] << target
|
|
end
|
|
end
|
|
|
|
if params[:title].present? && params[:raw].present? &&
|
|
(
|
|
params[:target_usernames].present? || params[:target_group_names].present? ||
|
|
params[:target_emails].present?
|
|
)
|
|
params[:archetype] = Archetype.private_message
|
|
|
|
creator = PostCreator.new(topic_poster, params)
|
|
post = creator.create
|
|
|
|
if creator.errors.present?
|
|
messages = creator.errors.full_messages.join(" ")
|
|
log_error("failed to create message", messages)
|
|
elsif user && action["skip_redirect"].blank?
|
|
@submission.redirect_on_complete = post.topic.url
|
|
end
|
|
|
|
if creator.errors.blank?
|
|
log_success("created message", "id: #{post.topic.id}")
|
|
result.handler = creator
|
|
result.output = post.topic.id
|
|
end
|
|
else
|
|
log_error(
|
|
"invalid message params",
|
|
"title: #{params[:title]}; post: #{params[:raw]}; recipients: #{params[:target_usernames]}",
|
|
)
|
|
end
|
|
end
|
|
|
|
def update_profile
|
|
params = {}
|
|
|
|
if (profile_updates = action["profile_updates"])
|
|
profile_updates.first[:pairs].each do |pair|
|
|
if allowed_profile_field?(pair["key"])
|
|
key = cast_profile_key(pair["key"])
|
|
value =
|
|
cast_profile_value(mapper.map_field(pair["value"], pair["value_type"]), pair["key"])
|
|
|
|
if user_field?(pair["key"])
|
|
params[:custom_fields] ||= {}
|
|
params[:custom_fields][key] = value
|
|
else
|
|
params[key.to_sym] = value
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
params = add_custom_fields(params)
|
|
|
|
if params.present?
|
|
result = UserUpdater.new(Discourse.system_user, user).update(params)
|
|
|
|
result = update_avatar(params[:avatar]) if params[:avatar].present?
|
|
|
|
if result
|
|
log_success("updated profile fields", "fields: #{params.keys.map(&:to_s).join(",")}")
|
|
else
|
|
log_error("failed to update profile fields", "result: #{result.inspect}")
|
|
end
|
|
else
|
|
log_error("invalid profile fields params", "params: #{params.inspect}")
|
|
end
|
|
end
|
|
|
|
def watch_tags
|
|
tags = CustomWizard::Mapper.new(inputs: action["tags"], data: mapper_data, user: user).perform
|
|
|
|
tags = [*tags]
|
|
level = action["notification_level"].to_sym
|
|
|
|
if level.blank?
|
|
log_error("Notifcation Level was not set. Exiting watch tags action")
|
|
return
|
|
end
|
|
|
|
users = []
|
|
|
|
if action["usernames"]
|
|
mapped_users =
|
|
CustomWizard::Mapper.new(inputs: action["usernames"], data: mapper_data, user: user).perform
|
|
|
|
if mapped_users.present?
|
|
mapped_users = mapped_users.split(",").map { |username| User.find_by(username: username) }
|
|
users.push(*mapped_users)
|
|
end
|
|
end
|
|
|
|
users.push(user) if ActiveRecord::Type::Boolean.new.cast(action["wizard_user"])
|
|
|
|
users.each do |user|
|
|
result = TagUser.batch_set(user, level, tags)
|
|
|
|
if result
|
|
log_success("#{user.username} notifications for #{tags} set to #{level}")
|
|
else
|
|
log_error("failed to set #{user.username} notifications for #{tags} to #{level}")
|
|
end
|
|
end
|
|
end
|
|
|
|
def watch_categories
|
|
watched_categories =
|
|
CustomWizard::Mapper.new(inputs: action["categories"], data: mapper_data, user: user).perform
|
|
|
|
watched_categories = [*watched_categories].map(&:to_i)
|
|
|
|
notification_level = action["notification_level"]
|
|
|
|
if notification_level.blank?
|
|
log_error("Notifcation Level was not set. Exiting wizard action")
|
|
return
|
|
end
|
|
|
|
mute_remainder =
|
|
CustomWizard::Mapper.new(
|
|
inputs: action["mute_remainder"],
|
|
data: mapper_data,
|
|
user: user,
|
|
).perform
|
|
|
|
users = []
|
|
|
|
if action["usernames"]
|
|
mapped_users =
|
|
CustomWizard::Mapper.new(inputs: action["usernames"], data: mapper_data, user: user).perform
|
|
|
|
if mapped_users.present?
|
|
mapped_users = mapped_users.split(",").map { |username| User.find_by(username: username) }
|
|
users.push(*mapped_users)
|
|
end
|
|
end
|
|
|
|
users.push(user) if ActiveRecord::Type::Boolean.new.cast(action["wizard_user"])
|
|
|
|
category_ids = Category.all.pluck(:id)
|
|
set_level = CategoryUser.notification_levels[notification_level.to_sym]
|
|
mute_level = CategoryUser.notification_levels[:muted]
|
|
|
|
users.each do |user|
|
|
category_ids.each do |category_id|
|
|
new_level = nil
|
|
|
|
if watched_categories.include?(category_id) && set_level != nil
|
|
new_level = set_level
|
|
elsif mute_remainder
|
|
new_level = mute_level
|
|
end
|
|
|
|
CategoryUser.set_notification_level_for_category(user, new_level, category_id) if new_level
|
|
end
|
|
|
|
if watched_categories.any?
|
|
log_success("#{user.username} notifications for #{watched_categories} set to #{set_level}")
|
|
end
|
|
|
|
log_success("#{user.username} notifications for all other categories muted") if mute_remainder
|
|
end
|
|
end
|
|
|
|
def send_to_api
|
|
api_body = nil
|
|
|
|
if action["api_body"] != ""
|
|
begin
|
|
api_body_parsed = JSON.parse(action["api_body"])
|
|
rescue JSON::ParserError
|
|
raise Discourse::InvalidParameters,
|
|
"Invalid API body definition: #{action["api_body"]} for #{action["title"]}"
|
|
end
|
|
api_body = JSON.parse(mapper.interpolate(JSON.generate(api_body_parsed)))
|
|
end
|
|
|
|
result =
|
|
CustomWizard::Api::Endpoint.request(user, action["api"], action["api_endpoint"], api_body)
|
|
|
|
if error = result["error"] || (result[0] && result[0]["error"])
|
|
error = error["message"] || error
|
|
log_error("api request failed", "message: #{error}")
|
|
else
|
|
log_success("api request succeeded", "result: #{result}")
|
|
end
|
|
end
|
|
|
|
def open_composer
|
|
params = basic_topic_params
|
|
|
|
if params[:title].present? && params[:raw].present?
|
|
url = "/new-topic?title=#{encode_query_param(params[:title])}"
|
|
url += "&body=#{encode_query_param(params[:raw])}"
|
|
|
|
if category_id = action_category
|
|
url += "&category_id=#{category_id}"
|
|
end
|
|
|
|
if tags = action_tags
|
|
url += "&tags=#{tags.join(",")}"
|
|
end
|
|
|
|
route_to = Discourse.base_uri + url
|
|
@result.output = @submission.route_to = route_to
|
|
|
|
log_success("route: #{route_to}")
|
|
else
|
|
log_error("invalid composer params", "title: #{params[:title]}; post: #{params[:raw]}")
|
|
end
|
|
end
|
|
|
|
def add_to_group
|
|
group_map =
|
|
CustomWizard::Mapper.new(
|
|
inputs: action["group"],
|
|
data: mapper_data,
|
|
user: user,
|
|
opts: {
|
|
multiple: true,
|
|
},
|
|
).perform
|
|
|
|
group_map = group_map.flatten.compact
|
|
|
|
if group_map.blank?
|
|
log_error("invalid group map")
|
|
return
|
|
end
|
|
|
|
groups =
|
|
group_map.reduce([]) do |result, g|
|
|
begin
|
|
result.push(Integer(g))
|
|
rescue ArgumentError
|
|
group = Group.find_by(name: g)
|
|
result.push(group.id) if group
|
|
end
|
|
|
|
result
|
|
end
|
|
|
|
result = nil
|
|
|
|
if groups.present?
|
|
groups.each do |group_id|
|
|
group = Group.find_by(id: group_id) if group_id
|
|
result = group.add(user) if group
|
|
end
|
|
end
|
|
|
|
if result
|
|
log_success("added to groups", "groups: #{groups.map(&:to_s).join(",")}")
|
|
else
|
|
detail = groups.present? ? "groups: #{groups.map(&:to_s).join(",")}" : nil
|
|
log_error("failed to add to groups", detail)
|
|
end
|
|
end
|
|
|
|
def route_to
|
|
return if (url_input = action["url"]).blank?
|
|
|
|
if url_input.is_a?(String)
|
|
url = mapper.interpolate(url_input)
|
|
else
|
|
url = CustomWizard::Mapper.new(inputs: url_input, data: mapper_data, user: user).perform
|
|
end
|
|
|
|
if action["code"].present?
|
|
@submission.fields[action["code"]] = SecureRandom.hex(8)
|
|
url += "&#{action["code"]}=#{@submission.fields[action["code"]]}"
|
|
end
|
|
|
|
route_to = UrlHelper.encode(url)
|
|
@submission.route_to = route_to
|
|
|
|
log_info("route: #{route_to}")
|
|
end
|
|
|
|
def create_group
|
|
group =
|
|
begin
|
|
Group.new(new_group_params.except(:usernames, :owner_usernames))
|
|
rescue ArgumentError => e
|
|
raise Discourse::InvalidParameters, "Invalid group params"
|
|
end
|
|
|
|
if group.save
|
|
def get_user_ids(username_string)
|
|
User.where(username: username_string.split(",")).pluck(:id)
|
|
end
|
|
|
|
if new_group_params[:owner_usernames].present?
|
|
owner_ids = get_user_ids(new_group_params[:owner_usernames])
|
|
owner_ids.each { |user_id| group.group_users.build(user_id: user_id, owner: true) }
|
|
end
|
|
|
|
if new_group_params[:usernames].present?
|
|
user_ids = get_user_ids(new_group_params[:usernames])
|
|
if user_ids.count < new_group_params[:usernames].count
|
|
log_error("Warning, group creation: some users were not found!")
|
|
end
|
|
user_ids -= owner_ids if owner_ids
|
|
user_ids.each { |user_id| group.group_users.build(user_id: user_id) }
|
|
end
|
|
|
|
log_success("Group created", group.name) if group.save
|
|
|
|
result.output = group.name
|
|
else
|
|
log_error("Group creation failed", group.errors.messages)
|
|
end
|
|
end
|
|
|
|
def create_category
|
|
category =
|
|
begin
|
|
Category.new(new_category_params.merge(user: user))
|
|
rescue ArgumentError => e
|
|
raise Discourse::InvalidParameters, "Invalid category params"
|
|
end
|
|
|
|
if category.save
|
|
StaffActionLogger.new(user).log_category_creation(category)
|
|
log_success("Category created", category.name)
|
|
result.output = category.id
|
|
else
|
|
log_error("Category creation failed", category.errors.messages)
|
|
end
|
|
end
|
|
|
|
def self.callbacks
|
|
@callbacks ||= {}
|
|
end
|
|
|
|
def self.register_callback(action, &block)
|
|
callbacks[action] ||= []
|
|
callbacks[action] << block
|
|
end
|
|
|
|
private
|
|
|
|
def action_category
|
|
output =
|
|
CustomWizard::Mapper.new(inputs: action["category"], data: mapper_data, user: user).perform
|
|
|
|
return false if output.blank?
|
|
|
|
if output.is_a?(Array)
|
|
output.first
|
|
elsif output.is_a?(Integer)
|
|
output
|
|
elsif output.is_a?(String)
|
|
output.to_i
|
|
end
|
|
end
|
|
|
|
def action_tags
|
|
output = CustomWizard::Mapper.new(inputs: action["tags"], data: mapper_data, user: user).perform
|
|
|
|
return false if output.blank?
|
|
|
|
if output.is_a?(Array)
|
|
output.flatten
|
|
else
|
|
output.is_a?(String)
|
|
[*output]
|
|
end
|
|
end
|
|
|
|
def add_custom_fields(params = {})
|
|
if (custom_fields = action["custom_fields"]).present?
|
|
field_map =
|
|
CustomWizard::Mapper.new(inputs: custom_fields, data: mapper_data, user: user).perform
|
|
registered_fields = CustomWizard::CustomField.full_list
|
|
|
|
field_map.each do |field|
|
|
keyArr = field[:key].split(".")
|
|
value = field[:value]
|
|
|
|
if keyArr.length > 1
|
|
klass = keyArr.first.to_sym
|
|
name = keyArr.second
|
|
|
|
if keyArr.length === 3 && name.include?("{}")
|
|
name = name.gsub("{}", "")
|
|
json_attr = keyArr.last
|
|
type = :json
|
|
end
|
|
else
|
|
name = keyArr.first
|
|
end
|
|
|
|
registered = registered_fields.select { |f| f.name == name }.first
|
|
if registered.present?
|
|
klass = registered.klass.to_sym
|
|
type = registered.type.to_sym
|
|
end
|
|
|
|
next if type === :json && json_attr.blank?
|
|
|
|
if klass === :topic
|
|
params[:topic_opts] ||= {}
|
|
params[:topic_opts][:custom_fields] ||= {}
|
|
|
|
if type === :json
|
|
params[:topic_opts][:custom_fields][name] ||= {}
|
|
params[:topic_opts][:custom_fields][name][json_attr] = value
|
|
else
|
|
params[:topic_opts][:custom_fields][name] = value
|
|
end
|
|
else
|
|
if type === :json
|
|
params[:custom_fields][name] ||= {}
|
|
params[:custom_fields][name][json_attr] = value
|
|
else
|
|
params[:custom_fields] ||= {}
|
|
params[:custom_fields][name] = value
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
params
|
|
end
|
|
|
|
def basic_topic_params
|
|
params = {
|
|
skip_validations: true,
|
|
topic_opts: {
|
|
custom_fields: {
|
|
wizard_submission_id: @wizard.current_submission.id,
|
|
},
|
|
},
|
|
}
|
|
|
|
params[:title] = CustomWizard::Mapper.new(
|
|
inputs: action["title"],
|
|
data: mapper_data,
|
|
user: user,
|
|
).perform
|
|
|
|
params[:raw] = (
|
|
if action["post_builder"]
|
|
mapper.interpolate(
|
|
action["post_template"],
|
|
user: true,
|
|
value: true,
|
|
wizard: true,
|
|
template: true,
|
|
)
|
|
else
|
|
@submission.fields[action["post"]]
|
|
end
|
|
)
|
|
|
|
params[:import_mode] = ActiveRecord::Type::Boolean.new.cast(action["suppress_notifications"])
|
|
|
|
add_custom_fields(params)
|
|
end
|
|
|
|
def public_topic_params
|
|
params = {}
|
|
|
|
if category = action_category
|
|
params[:category] = category
|
|
end
|
|
|
|
if tags = action_tags
|
|
params[:tags] = tags
|
|
end
|
|
|
|
if public_topic_fields.any?
|
|
public_topic_fields.each do |field|
|
|
unless action[field].nil? || action[field] == ""
|
|
params[field.to_sym] = CustomWizard::Mapper.new(
|
|
inputs: action[field],
|
|
data: mapper_data,
|
|
user: user,
|
|
).perform
|
|
end
|
|
end
|
|
end
|
|
|
|
params
|
|
end
|
|
|
|
def topic_poster
|
|
@topic_poster ||=
|
|
begin
|
|
poster_id =
|
|
CustomWizard::Mapper.new(inputs: action["poster"], data: mapper_data, user: user).perform
|
|
poster_id = [*poster_id].first if poster_id.present?
|
|
|
|
if poster_id.blank? || poster_id === WIZARD_USER
|
|
poster = user || guest_user
|
|
else
|
|
poster = User.find_by_username(poster_id)
|
|
end
|
|
|
|
poster || Discourse.system_user
|
|
end
|
|
end
|
|
|
|
def guest_user
|
|
@guest_user ||=
|
|
begin
|
|
return nil unless action["guest_email"]
|
|
|
|
email = CustomWizard::Mapper.new(inputs: action["guest_email"], data: mapper_data).perform
|
|
|
|
if email&.match(/@/)
|
|
if user = User.find_by_email(email)
|
|
user
|
|
else
|
|
User.create!(
|
|
email: email,
|
|
username: UserNameSuggester.suggest(email),
|
|
name: User.suggest_name(email),
|
|
staged: true,
|
|
)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def new_group_params
|
|
params = {}
|
|
|
|
%w[
|
|
name
|
|
full_name
|
|
title
|
|
bio_raw
|
|
owner_usernames
|
|
usernames
|
|
mentionable_level
|
|
messageable_level
|
|
visibility_level
|
|
members_visibility_level
|
|
grant_trust_level
|
|
].each do |attr|
|
|
input = action[attr]
|
|
|
|
raise ArgumentError.new if attr === "name" && input.blank?
|
|
|
|
input = action["name"] if attr === "full_name" && input.blank?
|
|
|
|
if input.present?
|
|
value = CustomWizard::Mapper.new(inputs: input, data: mapper_data, user: user).perform
|
|
|
|
if value
|
|
value = value.parameterize(separator: "_") if attr === "name"
|
|
value = value.to_i if attr.include?("_level")
|
|
|
|
params[attr.to_sym] = value
|
|
end
|
|
end
|
|
end
|
|
|
|
add_custom_fields(params)
|
|
end
|
|
|
|
def new_category_params
|
|
params = {}
|
|
|
|
%w[name slug color text_color parent_category_id permissions].each do |attr|
|
|
if action[attr].present?
|
|
value =
|
|
CustomWizard::Mapper.new(inputs: action[attr], data: mapper_data, user: user).perform
|
|
|
|
if value
|
|
value = value[0] if attr === "parent_category_id" && value.is_a?(Array)
|
|
|
|
if attr === "permissions" && value.is_a?(Array)
|
|
permissions = value
|
|
value = {}
|
|
|
|
permissions.each do |p|
|
|
k = p[:key]
|
|
v = p[:value].to_i
|
|
|
|
if k.is_a?(Array)
|
|
group = Group.find_by(id: k[0])
|
|
k = group.name
|
|
else
|
|
k = k.parameterize(separator: "_")
|
|
end
|
|
|
|
value[k] = v
|
|
end
|
|
end
|
|
|
|
value = value.parameterize(separator: "-") if attr === "slug"
|
|
|
|
params[attr.to_sym] = value
|
|
end
|
|
end
|
|
end
|
|
|
|
add_custom_fields(params)
|
|
end
|
|
|
|
def creates_post?
|
|
%i[create_topic send_message].include?(action["type"].to_sym)
|
|
end
|
|
|
|
def public_topic_fields
|
|
["visible"]
|
|
end
|
|
|
|
def profile_url_fields
|
|
%w[profile_background card_background]
|
|
end
|
|
|
|
def cast_profile_key(key)
|
|
if profile_url_fields.include?(key)
|
|
"#{key}_upload_url"
|
|
else
|
|
key
|
|
end
|
|
end
|
|
|
|
def cast_profile_value(value, key)
|
|
return value if value.nil?
|
|
|
|
if profile_url_fields.include?(key)
|
|
value["url"]
|
|
elsif key === "avatar"
|
|
value["id"]
|
|
else
|
|
value
|
|
end
|
|
end
|
|
|
|
def profile_excluded_fields
|
|
%w[username email trust_level].freeze
|
|
end
|
|
|
|
def allowed_profile_field?(field)
|
|
allowed_profile_fields.include?(field) || user_field?(field)
|
|
end
|
|
|
|
def user_field?(field)
|
|
field.to_s.include?(::User::USER_FIELD_PREFIX) &&
|
|
::UserField.exists?(field.split("_").last.to_i)
|
|
end
|
|
|
|
def allowed_profile_fields
|
|
CustomWizard::Mapper.user_fields.select { |f| profile_excluded_fields.exclude?(f) } +
|
|
profile_url_fields + ["avatar"]
|
|
end
|
|
|
|
def update_avatar(upload_id)
|
|
user.create_user_avatar unless user.user_avatar
|
|
user.user_avatar.custom_upload_id = upload_id
|
|
user.uploaded_avatar_id = upload_id
|
|
user.save!
|
|
user.user_avatar.save!
|
|
end
|
|
|
|
def encode_query_param(param)
|
|
Addressable::URI.encode_component(param, Addressable::URI::CharacterClasses::UNRESERVED)
|
|
end
|
|
|
|
def log_success(message, detail = nil)
|
|
@log.push("success: #{message} - #{detail}")
|
|
@result.success = true
|
|
end
|
|
|
|
def log_error(message, detail = nil)
|
|
@log.push("error: #{message} - #{detail}")
|
|
@result.success = false
|
|
end
|
|
|
|
def log_info(message, detail = nil)
|
|
@log.push("info: #{message} - #{detail}")
|
|
end
|
|
|
|
def save_log
|
|
username = user ? user.username : @wizard.actor_id
|
|
|
|
CustomWizard::Log.create(@wizard.id, action["type"], username, @log.join("; "))
|
|
end
|
|
end
|