0
0
Fork 1
Spiegel von https://github.com/paviliondev/discourse-custom-wizard.git synchronisiert 2024-11-27 11:20:28 +01:00
discourse-custom-wizard/lib/custom_wizard/wizard.rb

405 Zeilen
9,3 KiB
Ruby

2021-03-11 07:30:15 +01:00
# frozen_string_literal: true
2017-10-15 05:58:22 +02:00
require_dependency 'wizard/step'
require_dependency 'wizard/field'
require_dependency 'wizard/step_updater'
require_dependency 'wizard/builder'
2017-09-23 04:34:07 +02:00
class CustomWizard::Wizard
include ActiveModel::SerializerSupport
2017-09-23 04:34:07 +02:00
2017-11-01 05:21:14 +01:00
attr_accessor :id,
:name,
:background,
2020-04-13 14:17:22 +02:00
:theme_id,
2017-11-01 05:21:14 +01:00
:save_submissions,
:multiple_submissions,
:after_time,
:after_time_scheduled,
2017-11-01 05:21:14 +01:00
:after_signup,
2017-11-22 10:34:21 +01:00
:required,
:prompt_completion,
:restart_on_revisit,
:resume_on_revisit,
2020-03-30 08:16:03 +02:00
:permitted,
2020-04-13 14:17:22 +02:00
:steps,
2020-10-31 08:05:50 +01:00
:step_ids,
:field_ids,
:first_step,
:start,
2020-04-13 14:17:22 +02:00
:actions,
:action_ids,
:user,
2023-01-18 19:53:36 +01:00
:guest_id,
:submissions,
:template
2017-10-15 05:58:22 +02:00
attr_reader :all_step_ids
2023-01-18 19:53:36 +01:00
GUEST_ID_PREFIX ||= "guest"
GUEST_GROUP_ID = -1
2023-01-18 19:53:36 +01:00
def initialize(attrs = {}, user = nil, guest_id = nil)
if user
@user = user
elsif guest_id
@guest_id = guest_id
end
2020-11-03 01:24:20 +01:00
attrs = attrs.with_indifferent_access
2021-03-11 07:30:15 +01:00
2020-04-13 14:17:22 +02:00
@id = attrs['id']
@name = attrs['name']
@background = attrs['background']
2020-11-03 01:24:20 +01:00
@save_submissions = cast_bool(attrs['save_submissions'])
@multiple_submissions = cast_bool(attrs['multiple_submissions'])
@prompt_completion = cast_bool(attrs['prompt_completion'])
@restart_on_revisit = cast_bool(attrs['restart_on_revisit'])
@resume_on_revisit = cast_bool(attrs['resume_on_revisit'])
2020-11-03 01:24:20 +01:00
@after_signup = cast_bool(attrs['after_signup'])
@after_time = cast_bool(attrs['after_time'])
2020-04-13 14:17:22 +02:00
@after_time_scheduled = attrs['after_time_scheduled']
2020-11-03 01:24:20 +01:00
@required = cast_bool(attrs['required'])
2020-04-13 14:17:22 +02:00
@permitted = attrs['permitted'] || nil
@theme_id = attrs['theme_id']
2021-03-11 07:30:15 +01:00
2020-04-19 08:42:44 +02:00
if attrs['theme'].present?
theme = ::Theme.find_by(name: attrs['theme'])
2020-04-13 14:17:22 +02:00
@theme_id = theme.id if theme
2017-11-01 05:21:14 +01:00
end
2021-03-11 07:30:15 +01:00
2020-04-13 14:17:22 +02:00
@first_step = nil
@steps = []
2020-11-03 01:24:20 +01:00
if attrs['steps'].present?
@step_ids = @all_step_ids = attrs['steps'].map { |s| s['id'] }
@field_ids = []
attrs['steps'].each do |step|
if step['fields'].present?
step['fields'].each do |field|
@field_ids << field['id']
end
end
end
2020-11-03 01:24:20 +01:00
end
2021-03-11 07:30:15 +01:00
@actions = attrs['actions'] || []
@action_ids = @actions.map { |a| a['id'] }
@template = attrs
2017-10-15 05:58:22 +02:00
end
2021-03-11 07:30:15 +01:00
2023-01-18 19:53:36 +01:00
def actor_id
user ? user.id : guest_id
end
2020-11-03 01:24:20 +01:00
def cast_bool(val)
val.nil? ? false : ActiveRecord::Type::Boolean.new.cast(val)
end
2017-10-15 05:58:22 +02:00
def create_step(step_id)
::CustomWizard::Step.new(step_id)
2017-10-15 05:58:22 +02:00
end
def append_step(step)
step = create_step(step) if step.is_a?(String)
2021-03-11 07:30:15 +01:00
2017-10-15 05:58:22 +02:00
yield step if block_given?
2020-10-31 08:05:50 +01:00
steps << step
step.wizard = self
step.index = (steps.size == 1 ? 0 : steps.size) if step.index.nil?
end
def update!
update_step_order
update_step_ids
update_field_ids
update_action_ids
@submissions = nil
@current_submission = nil
true
end
def update_step_order
steps.sort_by!(&:index)
2021-03-11 07:30:15 +01:00
steps.each_with_index do |step, index|
if index === 0
@first_step = step
@start = step.id
else
last_step = steps[index - 1]
last_step.next = step
step.previous = last_step
end
step.index = index
if index === (steps.length - 1)
step.conditional_final_step = true
end
if index === (all_step_ids.length - 1)
step.last_step = true
end
if step.previous && step.previous.id === last_completed_step_id
@start = step.id
end
2017-10-15 05:58:22 +02:00
end
end
def last_completed_step_id
2023-01-18 19:53:36 +01:00
return nil unless actor_id && unfinished?
last_completed_step = CustomWizard::UserHistory.where(
actor_id: actor_id,
action: CustomWizard::UserHistory.actions[:step],
context: id,
subject: all_step_ids
).order("created_at").last
last_completed_step&.subject
2017-10-15 05:58:22 +02:00
end
def find_step(step_id)
steps.select { |step| step.id === step_id }.first
end
def create_updater(step_id, submission)
2017-11-01 05:21:14 +01:00
step = @steps.find { |s| s.id == step_id }
wizard = self
2023-01-18 19:53:36 +01:00
CustomWizard::StepUpdater.new(wizard, step, submission)
2017-11-01 05:21:14 +01:00
end
2017-10-15 05:58:22 +02:00
2017-11-01 05:21:14 +01:00
def unfinished?
2023-01-18 19:53:36 +01:00
return nil unless actor_id
2019-06-19 07:23:10 +02:00
2023-01-18 19:53:36 +01:00
most_recent = CustomWizard::UserHistory.where(
actor_id: actor_id,
action: CustomWizard::UserHistory.actions[:step],
2020-10-31 08:05:50 +01:00
context: id,
2017-11-02 05:15:30 +01:00
).distinct.order('updated_at DESC').first
2017-11-01 05:21:14 +01:00
2019-01-22 00:57:03 +01:00
if most_recent && most_recent.subject == "reset"
2019-01-14 03:53:53 +01:00
false
elsif most_recent
2020-11-03 01:24:20 +01:00
most_recent.subject != steps.last.id
2017-11-01 05:21:14 +01:00
else
true
end
end
def completed?
2023-01-18 19:53:36 +01:00
return nil unless actor_id
2021-03-11 07:30:15 +01:00
2023-01-18 19:53:36 +01:00
history = CustomWizard::UserHistory.where(
actor_id: actor_id,
action: CustomWizard::UserHistory.actions[:step],
2020-10-31 08:05:50 +01:00
context: id
2017-11-01 05:21:14 +01:00
)
2020-10-31 08:05:50 +01:00
if after_time
history = history.where("updated_at > ?", after_time_scheduled)
2017-11-01 05:21:14 +01:00
end
2021-03-11 07:30:15 +01:00
2017-11-01 05:21:14 +01:00
completed = history.distinct.order(:subject).pluck(:subject)
2020-10-31 08:05:50 +01:00
(step_ids - completed).empty?
2017-10-15 05:58:22 +02:00
end
2017-11-29 10:48:49 +01:00
def permitted?
2023-01-18 19:53:36 +01:00
return nil unless actor_id
return true if user && (user.admin? || permitted.blank?)
return false if !user && permitted.blank?
2021-03-11 07:30:15 +01:00
2020-04-06 10:36:38 +02:00
mapper = CustomWizard::Mapper.new(
inputs: permitted,
user: user,
opts: {
with_type: true,
multiple: true
}
).perform
2021-03-11 07:30:15 +01:00
2020-04-06 10:36:38 +02:00
return true if mapper.blank?
2021-03-11 07:30:15 +01:00
2020-04-06 10:36:38 +02:00
mapper.all? do |m|
if !user
m[:type] === 'assignment' && [*m[:result]].include?(GUEST_GROUP_ID)
2020-04-06 10:36:38 +02:00
else
if m[:type] === 'assignment'
[*m[:result]].include?(GUEST_GROUP_ID) ||
[*m[:result]].include?(Group::AUTO_GROUPS[:everyone]) ||
GroupUser.exists?(group_id: m[:result], user_id: user.id)
elsif m[:type] === 'validation'
m[:result]
else
true
end
2020-04-06 10:36:38 +02:00
end
end
2017-11-29 10:48:49 +01:00
end
2021-03-11 07:30:15 +01:00
2020-04-13 14:17:22 +02:00
def can_access?
permitted? && (user&.admin? || (multiple_submissions || !completed?))
2020-04-13 14:17:22 +02:00
end
2017-11-29 10:48:49 +01:00
2019-01-14 03:53:53 +01:00
def reset
2023-01-18 19:53:36 +01:00
return nil unless actor_id
CustomWizard::UserHistory.create(
action: CustomWizard::UserHistory.actions[:step],
actor_id: actor_id,
2020-10-31 08:05:50 +01:00
context: id,
2019-01-14 03:53:53 +01:00
subject: "reset"
)
end
2021-03-11 07:30:15 +01:00
def update_step_ids
@step_ids = steps.map(&:id)
end
def update_field_ids
@field_ids = steps.map { |step| step.fields.map { |field| field.id } }.flatten
end
def update_action_ids
@action_ids = []
@actions.each do |action|
if action['run_after'].blank? ||
action['run_after'] === 'wizard_completion' ||
step_ids.include?(action['run_after'])
@action_ids << action['id']
end
end
end
2020-04-13 14:17:22 +02:00
def submissions
2023-01-18 19:53:36 +01:00
@submissions ||= CustomWizard::Submission.list(self).submissions
2020-10-31 08:05:50 +01:00
end
2021-03-11 07:30:15 +01:00
2020-11-03 01:24:20 +01:00
def current_submission
@current_submission ||= begin
if submissions.present?
unsubmitted = submissions.select { |submission| !submission.submitted_at }
unsubmitted.present? ? unsubmitted.first : CustomWizard::Submission.new(self)
else
CustomWizard::Submission.new(self)
end
2021-05-06 23:58:16 +02:00
end
end
def cleanup_on_complete!
remove_user_redirect
if current_submission.present?
current_submission.submitted_at = Time.now.iso8601
current_submission.save
end
update!
2020-11-03 01:24:20 +01:00
end
2021-03-11 07:30:15 +01:00
def cleanup_on_skip!
remove_user_redirect
if current_submission.present?
current_submission.remove
end
reset
end
def remove_user_redirect
2023-01-18 19:53:36 +01:00
return unless user.present?
if id == user.redirect_to_wizard
user.custom_fields.delete('redirect_to_wizard')
user.save_custom_fields(true)
end
end
2023-01-18 19:53:36 +01:00
def self.create(wizard_id, user = nil, guest_id = nil)
2020-10-31 08:05:50 +01:00
if template = CustomWizard::Template.find(wizard_id)
2023-01-18 19:53:36 +01:00
new(template.to_h, user, guest_id)
2020-10-31 08:05:50 +01:00
else
false
end
2020-04-13 14:17:22 +02:00
end
2021-03-11 07:30:15 +01:00
2021-09-07 14:06:13 +02:00
def self.list(user, template_opts = {}, not_completed = false)
2020-11-03 01:24:20 +01:00
return [] unless user
2021-03-11 07:30:15 +01:00
2021-09-07 14:06:13 +02:00
CustomWizard::Template.list(**template_opts).reduce([]) do |result, template|
2020-11-03 01:24:20 +01:00
wizard = new(template, user)
2023-02-09 12:33:55 +01:00
result.push(wizard) if wizard.permitted? && (
!not_completed || !wizard.completed?
)
2020-11-03 01:24:20 +01:00
result
end
2020-03-30 08:16:03 +02:00
end
def self.after_signup(user)
2020-11-03 01:24:20 +01:00
wizards = list(
user,
2021-09-07 14:06:13 +02:00
{
2020-11-03 01:24:20 +01:00
setting: 'after_signup',
order: "(value::json ->> 'permitted') IS NOT NULL DESC"
}
)
wizards.any? ? wizards.first : false
2017-10-15 05:58:22 +02:00
end
2017-11-22 10:34:21 +01:00
def self.prompt_completion(user)
2020-11-03 01:24:20 +01:00
wizards = list(
user,
2021-09-07 14:06:13 +02:00
{
2020-11-03 01:24:20 +01:00
setting: 'prompt_completion',
order: "(value::json ->> 'permitted') IS NOT NULL DESC"
},
2021-09-07 14:06:13 +02:00
true
2020-11-03 01:24:20 +01:00
)
if wizards.any?
wizards.map do |w|
{
id: w.id,
name: w.name
}
2017-11-22 10:34:21 +01:00
end
else
false
end
end
def self.set_user_redirect(wizard_id, user)
2020-04-19 08:42:44 +02:00
wizard = self.create(wizard_id, user)
2021-03-11 07:30:15 +01:00
if wizard.permitted?
user.custom_fields['redirect_to_wizard'] = wizard_id
user.save_custom_fields(true)
else
false
end
end
def self.set_wizard_redirect(user, wizard_id, url)
wizard = self.create(wizard_id, user)
if wizard.permitted?
submission = wizard.current_submission
submission.redirect_to = url
submission.save
else
false
end
end
2023-01-18 19:53:36 +01:00
def self.generate_guest_id
"#{self::GUEST_ID_PREFIX}_#{SecureRandom.hex(12)}"
end
2017-09-23 04:34:07 +02:00
end