working builder and action specs
Dieser Commit ist enthalten in:
Ursprung
8fdd263d8e
Commit
b726d40a0c
15 geänderte Dateien mit 603 neuen und 393 gelöschten Zeilen
|
@ -4,7 +4,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
|
||||||
def index
|
def index
|
||||||
render_json_dump(
|
render_json_dump(
|
||||||
wizard_list: ActiveModel::ArraySerializer.new(
|
wizard_list: ActiveModel::ArraySerializer.new(
|
||||||
CustomWizard::Wizard.list,
|
CustomWizard::Template.list,
|
||||||
each_serializer: CustomWizard::BasicWizardSerializer
|
each_serializer: CustomWizard::BasicWizardSerializer
|
||||||
),
|
),
|
||||||
field_types: CustomWizard::Field.types
|
field_types: CustomWizard::Field.types
|
||||||
|
@ -14,7 +14,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
|
||||||
def show
|
def show
|
||||||
params.require(:wizard_id)
|
params.require(:wizard_id)
|
||||||
|
|
||||||
if data = CustomWizard::Wizard.find(params[:wizard_id].underscore)
|
if data = CustomWizard::Template.find(params[:wizard_id].underscore)
|
||||||
render json: data.as_json
|
render json: data.as_json
|
||||||
else
|
else
|
||||||
render json: { none: true }
|
render json: { none: true }
|
||||||
|
@ -22,8 +22,11 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove
|
def remove
|
||||||
CustomWizard::Wizard.remove(@wizard.id)
|
if CustomWizard::Template.remove(@wizard.id)
|
||||||
render json: success_json
|
render json: success_json
|
||||||
|
else
|
||||||
|
render json: failed_json
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def save
|
def save
|
||||||
|
@ -36,7 +39,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
|
||||||
if validation[:error]
|
if validation[:error]
|
||||||
render json: { error: validation[:error] }
|
render json: { error: validation[:error] }
|
||||||
else
|
else
|
||||||
if wizard_id = CustomWizard::Wizard.save(validation[:wizard])
|
if wizard_id = CustomWizard::Template.save(validation[:wizard])
|
||||||
render json: success_json.merge(wizard_id: wizard_id)
|
render json: success_json.merge(wizard_id: wizard_id)
|
||||||
else
|
else
|
||||||
render json: failed_json
|
render json: failed_json
|
||||||
|
|
|
@ -1,19 +1,30 @@
|
||||||
class CustomWizard::StepsController < ::ApplicationController
|
class CustomWizard::StepsController < ::ApplicationController
|
||||||
before_action :ensure_logged_in
|
before_action :ensure_logged_in
|
||||||
|
before_action :ensure_can_update
|
||||||
|
|
||||||
def update
|
def update
|
||||||
params.require(:step_id)
|
params.require(:step_id)
|
||||||
params.require(:wizard_id)
|
params.require(:wizard_id)
|
||||||
field_ids = CustomWizard::Wizard.field_ids(params[:wizard_id], params[:step_id])
|
|
||||||
|
|
||||||
permitted = params.permit(:wizard_id, :step_id)
|
wizard = @builder.build
|
||||||
if params[:fields]
|
step = wizard.steps.select { |s| s.id == update_params[:step_id] }.first
|
||||||
permitted[:fields] = params[:fields].select { |k, v| field_ids.include? k }
|
|
||||||
permitted.permit!
|
if !step || step.fields.blank?
|
||||||
|
raise Discourse::InvalidParameters.new(:step_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
wizard = CustomWizard::Builder.new(permitted[:wizard_id].underscore, current_user).build
|
field_ids = step.fields.map(&:id)
|
||||||
updater = wizard.create_updater(permitted[:step_id], permitted[:fields])
|
|
||||||
|
if params[:fields]
|
||||||
|
permitted_fields = params[:fields].select { |k, v| field_ids.include? k }
|
||||||
|
update_params[:fields] = permitted_fields
|
||||||
|
update_params.permit!
|
||||||
|
end
|
||||||
|
|
||||||
|
updater = wizard.create_updater(
|
||||||
|
update_params[:step_id],
|
||||||
|
update_params[:fields]
|
||||||
|
)
|
||||||
updater.update
|
updater.update
|
||||||
|
|
||||||
if updater.success?
|
if updater.success?
|
||||||
|
@ -29,4 +40,25 @@ class CustomWizard::StepsController < ::ApplicationController
|
||||||
render json: { errors: errors }, status: 422
|
render json: { errors: errors }, status: 422
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def ensure_can_update
|
||||||
|
@builder = CustomWizard::Builder.new(
|
||||||
|
update_params[:wizard_id].underscore,
|
||||||
|
current_user
|
||||||
|
)
|
||||||
|
|
||||||
|
if @builder.nil?
|
||||||
|
raise Discourse::InvalidParameters.new(:wizard_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
if !@builder.wizard || !@builder.wizard.can_access?
|
||||||
|
raise Discourse::InvalidAccess.new
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def update_params
|
||||||
|
params.permit(:wizard_id, :step_id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,7 +24,7 @@ class CustomWizard::WizardController < ::ApplicationController
|
||||||
|
|
||||||
if builder.wizard.present?
|
if builder.wizard.present?
|
||||||
builder_opts = {}
|
builder_opts = {}
|
||||||
builder_opts[:reset] = params[:reset] || builder.wizard.restart_on_revisit
|
builder_opts[:reset] = params[:reset]
|
||||||
built_wizard = builder.build(builder_opts, params)
|
built_wizard = builder.build(builder_opts, params)
|
||||||
|
|
||||||
render_serialized(built_wizard, ::CustomWizard::WizardSerializer, root: false)
|
render_serialized(built_wizard, ::CustomWizard::WizardSerializer, root: false)
|
||||||
|
|
|
@ -2,13 +2,13 @@ class CustomWizard::Builder
|
||||||
attr_accessor :wizard, :updater, :submissions
|
attr_accessor :wizard, :updater, :submissions
|
||||||
|
|
||||||
def initialize(wizard_id, user=nil)
|
def initialize(wizard_id, user=nil)
|
||||||
params = CustomWizard::Wizard.find(wizard_id)
|
template = CustomWizard::Template.find(wizard_id)
|
||||||
return nil if params.blank?
|
return nil if template.blank?
|
||||||
|
|
||||||
@wizard = CustomWizard::Wizard.new(params, user)
|
@wizard = CustomWizard::Wizard.new(template, user)
|
||||||
@steps = params['steps'] || []
|
@steps = template['steps'] || []
|
||||||
@actions = params['actions'] || []
|
@actions = template['actions'] || []
|
||||||
@submissions = @wizard.submissions if user && @wizard
|
@submissions = @wizard.submissions
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.sorted_handlers
|
def self.sorted_handlers
|
||||||
|
@ -48,12 +48,27 @@ class CustomWizard::Builder
|
||||||
return nil if !SiteSetting.custom_wizard_enabled || !@wizard
|
return nil if !SiteSetting.custom_wizard_enabled || !@wizard
|
||||||
return @wizard if !@wizard.can_access?
|
return @wizard if !@wizard.can_access?
|
||||||
|
|
||||||
|
build_opts[:reset] = build_opts[:reset] || @wizard.restart_on_revisit
|
||||||
reset_submissions if build_opts[:reset]
|
reset_submissions if build_opts[:reset]
|
||||||
|
|
||||||
@steps.each do |step_template|
|
@steps.each do |step_template|
|
||||||
@wizard.append_step(step_template['id']) do |step|
|
@wizard.append_step(step_template['id']) do |step|
|
||||||
|
step.permitted = true
|
||||||
|
|
||||||
|
if step_template['required_data']
|
||||||
|
step = ensure_required_data(step, step_template)
|
||||||
|
end
|
||||||
|
|
||||||
|
if !step.permitted
|
||||||
|
if step_template['required_data_message']
|
||||||
|
step.permitted_message = step_template['required_data_message']
|
||||||
|
end
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
step.title = step_template['title'] if step_template['title']
|
step.title = step_template['title'] if step_template['title']
|
||||||
step.banner = step_template['banner'] if step_template['banner']
|
step.banner = step_template['banner'] if step_template['banner']
|
||||||
|
step.key = step_template['key'] if step_template['key']
|
||||||
|
|
||||||
if step_template['description']
|
if step_template['description']
|
||||||
step.description = mapper.interpolate(
|
step.description = mapper.interpolate(
|
||||||
|
@ -63,59 +78,8 @@ class CustomWizard::Builder
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
step.key = step_template['key'] if step_template['key']
|
|
||||||
step.permitted = true
|
|
||||||
|
|
||||||
if permitted_params = step_template['permitted_params']
|
if permitted_params = step_template['permitted_params']
|
||||||
permitted_data = {}
|
save_permitted_params(permitted_params, params)
|
||||||
|
|
||||||
permitted_params.each do |p|
|
|
||||||
pair = p['pairs'].first
|
|
||||||
params_key = pair['key'].to_sym
|
|
||||||
submission_key = pair['value'].to_sym
|
|
||||||
permitted_data[submission_key] = params[params_key] if params[params_key]
|
|
||||||
end
|
|
||||||
|
|
||||||
if permitted_data.present?
|
|
||||||
current_data = @submissions.last || {}
|
|
||||||
save_submissions(current_data.merge(permitted_data), false)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if (required_data = step_template['required_data']).present?
|
|
||||||
has_required_data = true
|
|
||||||
|
|
||||||
required_data.each do |required|
|
|
||||||
required['pairs'].each do |pair|
|
|
||||||
if pair['key'].blank? || pair['value'].blank?
|
|
||||||
has_required_data = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if has_required_data
|
|
||||||
if !@submissions.last
|
|
||||||
step.permitted = false
|
|
||||||
else
|
|
||||||
required_data.each do |required|
|
|
||||||
pairs = required['pairs'].map do |p|
|
|
||||||
p['key'] = @submissions.last[p['key']]
|
|
||||||
end
|
|
||||||
|
|
||||||
unless mapper.validate_pairs(pairs)
|
|
||||||
step.permitted = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if !step.permitted
|
|
||||||
if step_template['required_data_message']
|
|
||||||
step.permitted_message = step_template['required_data_message']
|
|
||||||
end
|
|
||||||
|
|
||||||
next
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if step_template['fields'] && step_template['fields'].length
|
if step_template['fields'] && step_template['fields'].length
|
||||||
|
@ -211,6 +175,8 @@ class CustomWizard::Builder
|
||||||
params[:description] = field_template['description'] if field_template['description']
|
params[:description] = field_template['description'] if field_template['description']
|
||||||
params[:image] = field_template['image'] if field_template['image']
|
params[:image] = field_template['image'] if field_template['image']
|
||||||
params[:key] = field_template['key'] if field_template['key']
|
params[:key] = field_template['key'] if field_template['key']
|
||||||
|
params[:min_length] = field_template['min_length'] if field_template['min_length']
|
||||||
|
params[:value] = prefill_field(field_template, step_template)
|
||||||
|
|
||||||
## Load previously submitted values
|
## Load previously submitted values
|
||||||
if !build_opts[:reset] && @submissions.last && !@submissions.last.key?("submitted_at")
|
if !build_opts[:reset] && @submissions.last && !@submissions.last.key?("submitted_at")
|
||||||
|
@ -218,8 +184,6 @@ class CustomWizard::Builder
|
||||||
params[:value] = submission[field_template['id']] if submission[field_template['id']]
|
params[:value] = submission[field_template['id']] if submission[field_template['id']]
|
||||||
end
|
end
|
||||||
|
|
||||||
params[:value] = prefill_field(field_template, step_template) || params[:value]
|
|
||||||
|
|
||||||
if field_template['type'] === 'group' && params[:value].present?
|
if field_template['type'] === 'group' && params[:value].present?
|
||||||
params[:value] = params[:value].first
|
params[:value] = params[:value].first
|
||||||
end
|
end
|
||||||
|
@ -404,4 +368,44 @@ class CustomWizard::Builder
|
||||||
PluginStore.set("#{@wizard.id}_submissions", @wizard.user.id, @submissions)
|
PluginStore.set("#{@wizard.id}_submissions", @wizard.user.id, @submissions)
|
||||||
@wizard.reset
|
@wizard.reset
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def save_permitted_params(permitted_params, params)
|
||||||
|
permitted_data = {}
|
||||||
|
|
||||||
|
permitted_params.each do |pp|
|
||||||
|
pair = pp['pairs'].first
|
||||||
|
params_key = pair['key'].to_sym
|
||||||
|
submission_key = pair['value'].to_sym
|
||||||
|
permitted_data[submission_key] = params[params_key] if params[params_key]
|
||||||
|
end
|
||||||
|
|
||||||
|
if permitted_data.present?
|
||||||
|
current_data = @submissions.last || {}
|
||||||
|
save_submissions(current_data.merge(permitted_data), false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def ensure_required_data(step, step_template)
|
||||||
|
step_template['required_data'].each do |required|
|
||||||
|
pairs = required['pairs'].select do |pair|
|
||||||
|
pair['key'].present? && pair['value'].present?
|
||||||
|
end
|
||||||
|
|
||||||
|
if pairs.any? && !@submissions.last
|
||||||
|
step.permitted = false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
pairs.each do |pair|
|
||||||
|
pair['key'] = @submissions.last[pair['key']]
|
||||||
|
end
|
||||||
|
|
||||||
|
if !mapper.validate_pairs(pairs)
|
||||||
|
step.permitted = false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
step
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
81
lib/custom_wizard/template.rb
Normale Datei
81
lib/custom_wizard/template.rb
Normale Datei
|
@ -0,0 +1,81 @@
|
||||||
|
class CustomWizard::Template
|
||||||
|
def self.add(obj)
|
||||||
|
wizard = obj.is_a?(String) ? ::JSON.parse(json) : obj
|
||||||
|
PluginStore.set('custom_wizard', wizard["id"], wizard)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.find(wizard_id)
|
||||||
|
PluginStore.get('custom_wizard', wizard_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.save(data)
|
||||||
|
data = data.with_indifferent_access
|
||||||
|
existing = self.find(data[:id])
|
||||||
|
|
||||||
|
data[:steps].each do |step|
|
||||||
|
if step[:raw_description]
|
||||||
|
step[:description] = PrettyText.cook(step[:raw_description])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
data = data.slice!(:create)
|
||||||
|
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
PluginStore.set('custom_wizard', data[:id], data)
|
||||||
|
|
||||||
|
if data[:after_time]
|
||||||
|
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: data[:id])
|
||||||
|
enqueue_at = Time.parse(data[:after_time_scheduled]).utc
|
||||||
|
Jobs.enqueue_at(enqueue_at, :set_after_time_wizard, wizard_id: data[:id])
|
||||||
|
end
|
||||||
|
|
||||||
|
if existing && existing[:after_time] && !data[:after_time]
|
||||||
|
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: data[:id])
|
||||||
|
Jobs.enqueue(:clear_after_time_wizard, wizard_id: data[:id])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
data[:id]
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.remove(wizard_id)
|
||||||
|
wizard = self.create(wizard_id)
|
||||||
|
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
if wizard.after_time
|
||||||
|
Jobs.cancel_scheduled_job(:set_after_time_wizard)
|
||||||
|
Jobs.enqueue(:clear_after_time_wizard, wizard_id: wizard.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
PluginStore.remove('custom_wizard', wizard.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.exists?(wizard_id)
|
||||||
|
PluginStoreRow.exists?(plugin_name: 'custom_wizard', key: wizard_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.list(user=nil)
|
||||||
|
PluginStoreRow.where(plugin_name: 'custom_wizard').order(:id)
|
||||||
|
.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.setting_enabled(attr)
|
||||||
|
PluginStoreRow.where("
|
||||||
|
plugin_name = 'custom_wizard' AND
|
||||||
|
(value::json ->> '#{attr}')::boolean IS TRUE
|
||||||
|
")
|
||||||
|
end
|
||||||
|
end
|
|
@ -95,7 +95,7 @@ class CustomWizard::Validator
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_id(object, type)
|
def check_id(object, type)
|
||||||
if type === :wizard && @opts[:create] && CustomWizard::Wizard.exists?(object[:id])
|
if type === :wizard && @opts[:create] && CustomWizard::Template.exists?(object[:id])
|
||||||
@error = {
|
@error = {
|
||||||
type: 'conflict',
|
type: 'conflict',
|
||||||
params: { type: type, property: 'id', value: object[:id] }
|
params: { type: type, property: 'id', value: object[:id] }
|
||||||
|
|
|
@ -24,6 +24,7 @@ class CustomWizard::Wizard
|
||||||
:needs_categories,
|
:needs_categories,
|
||||||
:needs_groups,
|
:needs_groups,
|
||||||
:steps,
|
:steps,
|
||||||
|
:step_ids,
|
||||||
:actions,
|
:actions,
|
||||||
:user
|
:user
|
||||||
|
|
||||||
|
@ -52,6 +53,7 @@ class CustomWizard::Wizard
|
||||||
end
|
end
|
||||||
|
|
||||||
@first_step = nil
|
@first_step = nil
|
||||||
|
@step_ids = attrs['steps'].map { |s| s['id'] }
|
||||||
@steps = []
|
@steps = []
|
||||||
@actions = []
|
@actions = []
|
||||||
end
|
end
|
||||||
|
@ -65,13 +67,11 @@ class CustomWizard::Wizard
|
||||||
|
|
||||||
yield step if block_given?
|
yield step if block_given?
|
||||||
|
|
||||||
last_step = @steps.last
|
last_step = steps.last
|
||||||
|
steps << step
|
||||||
|
|
||||||
@steps << step
|
if steps.size == 1
|
||||||
|
first_step = step
|
||||||
# If it's the first step
|
|
||||||
if @steps.size == 1
|
|
||||||
@first_step = step
|
|
||||||
step.index = 0
|
step.index = 0
|
||||||
elsif last_step.present?
|
elsif last_step.present?
|
||||||
last_step.next = step
|
last_step.next = step
|
||||||
|
@ -81,67 +81,62 @@ class CustomWizard::Wizard
|
||||||
end
|
end
|
||||||
|
|
||||||
def start
|
def start
|
||||||
return nil if !@user
|
return nil if !user
|
||||||
|
|
||||||
if unfinished? && last_completed_step = ::UserHistory.where(
|
if unfinished? && last_completed_step = ::UserHistory.where(
|
||||||
acting_user_id: @user.id,
|
acting_user_id: user.id,
|
||||||
action: ::UserHistory.actions[:custom_wizard_step],
|
action: ::UserHistory.actions[:custom_wizard_step],
|
||||||
context: @id,
|
context: id,
|
||||||
subject: @steps.map(&:id)
|
subject: steps.map(&:id)
|
||||||
).order("created_at").last
|
).order("created_at").last
|
||||||
|
|
||||||
step_id = last_completed_step.subject
|
step_id = last_completed_step.subject
|
||||||
last_index = @steps.index { |s| s.id == step_id }
|
last_index = steps.index { |s| s.id == step_id }
|
||||||
@steps[last_index + 1]
|
steps[last_index + 1]
|
||||||
else
|
else
|
||||||
@first_step
|
first_step
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_updater(step_id, fields)
|
def create_updater(step_id, fields)
|
||||||
step = @steps.find { |s| s.id == step_id }
|
step = @steps.find { |s| s.id == step_id }
|
||||||
wizard = self
|
wizard = self
|
||||||
CustomWizard::StepUpdater.new(@user, wizard, step, fields)
|
CustomWizard::StepUpdater.new(user, wizard, step, fields)
|
||||||
end
|
end
|
||||||
|
|
||||||
def unfinished?
|
def unfinished?
|
||||||
return nil if !@user
|
return nil if !user
|
||||||
|
|
||||||
most_recent = ::UserHistory.where(
|
most_recent = ::UserHistory.where(
|
||||||
acting_user_id: @user.id,
|
acting_user_id: user.id,
|
||||||
action: ::UserHistory.actions[:custom_wizard_step],
|
action: ::UserHistory.actions[:custom_wizard_step],
|
||||||
context: @id,
|
context: id,
|
||||||
).distinct.order('updated_at DESC').first
|
).distinct.order('updated_at DESC').first
|
||||||
|
|
||||||
if most_recent && most_recent.subject == "reset"
|
if most_recent && most_recent.subject == "reset"
|
||||||
false
|
false
|
||||||
elsif most_recent
|
elsif most_recent
|
||||||
last_finished_step = most_recent.subject
|
most_recent.subject != steps.last.id
|
||||||
last_step = CustomWizard::Wizard.step_ids(@id).last
|
|
||||||
last_finished_step != last_step
|
|
||||||
else
|
else
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def completed?
|
def completed?
|
||||||
return nil if !@user
|
return nil if !user
|
||||||
|
|
||||||
steps = CustomWizard::Wizard.step_ids(@id)
|
|
||||||
|
|
||||||
history = ::UserHistory.where(
|
history = ::UserHistory.where(
|
||||||
acting_user_id: @user.id,
|
acting_user_id: user.id,
|
||||||
action: ::UserHistory.actions[:custom_wizard_step],
|
action: ::UserHistory.actions[:custom_wizard_step],
|
||||||
context: @id
|
context: id
|
||||||
)
|
)
|
||||||
|
|
||||||
if @after_time
|
if after_time
|
||||||
history = history.where("updated_at > ?", @after_time_scheduled)
|
history = history.where("updated_at > ?", after_time_scheduled)
|
||||||
end
|
end
|
||||||
|
|
||||||
completed = history.distinct.order(:subject).pluck(:subject)
|
completed = history.distinct.order(:subject).pluck(:subject)
|
||||||
|
(step_ids - completed).empty?
|
||||||
(steps - completed).empty?
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def permitted?
|
def permitted?
|
||||||
|
@ -178,33 +173,38 @@ class CustomWizard::Wizard
|
||||||
def reset
|
def reset
|
||||||
::UserHistory.create(
|
::UserHistory.create(
|
||||||
action: ::UserHistory.actions[:custom_wizard_step],
|
action: ::UserHistory.actions[:custom_wizard_step],
|
||||||
acting_user_id: @user.id,
|
acting_user_id: user.id,
|
||||||
context: @id,
|
context: id,
|
||||||
subject: "reset"
|
subject: "reset"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def categories
|
def categories
|
||||||
@categories ||= ::Site.new(Guardian.new(@user)).categories
|
@categories ||= ::Site.new(Guardian.new(user)).categories
|
||||||
end
|
end
|
||||||
|
|
||||||
def groups
|
def groups
|
||||||
@groups ||= ::Site.new(Guardian.new(@user)).groups
|
@groups ||= ::Site.new(Guardian.new(user)).groups
|
||||||
end
|
end
|
||||||
|
|
||||||
def submissions
|
def submissions
|
||||||
Array.wrap(PluginStore.get("#{id}_submissions", @user.id))
|
Array.wrap(PluginStore.get("#{id}_submissions", user.id))
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.filter_records(filter)
|
def self.create(wizard_id, user = nil)
|
||||||
PluginStoreRow.where("
|
if template = CustomWizard::Template.find(wizard_id)
|
||||||
plugin_name = 'custom_wizard' AND
|
self.new(template.to_h, user)
|
||||||
(value::json ->> '#{filter}')::boolean IS TRUE
|
else
|
||||||
")
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.list(user=nil)
|
||||||
|
CustomWizard::Template.list.map { |template| self.new(template.to_h, user) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.after_signup(user)
|
def self.after_signup(user)
|
||||||
if (records = filter_records('after_signup')).any?
|
if (records = CustomWizard::Template.setting_enabled('after_signup')).any?
|
||||||
result = false
|
result = false
|
||||||
|
|
||||||
records
|
records
|
||||||
|
@ -225,9 +225,9 @@ class CustomWizard::Wizard
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.prompt_completion(user)
|
def self.prompt_completion(user)
|
||||||
if (records = filter_records('prompt_completion')).any?
|
if (records = CustomWizard::Template.setting_enabled('prompt_completion')).any?
|
||||||
records.reduce([]) do |result, record|
|
records.reduce([]) do |result, record|
|
||||||
wizard = CustomWizard::Wizard.new(::JSON.parse(record.value), user)
|
wizard = self.new(::JSON.parse(record.value), user)
|
||||||
|
|
||||||
if wizard.permitted? && !wizard.completed?
|
if wizard.permitted? && !wizard.completed?
|
||||||
result.push(id: wizard.id, name: wizard.name)
|
result.push(id: wizard.id, name: wizard.name)
|
||||||
|
@ -241,115 +241,13 @@ class CustomWizard::Wizard
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.restart_on_revisit
|
def self.restart_on_revisit
|
||||||
if (records = filter_records('restart_on_revisit')).any?
|
if (records = CustomWizard::Template.setting_enabled('restart_on_revisit')).any?
|
||||||
records.first.key
|
records.first.key
|
||||||
else
|
else
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.steps(wizard_id)
|
|
||||||
wizard = PluginStore.get('custom_wizard', wizard_id)
|
|
||||||
wizard ? wizard['steps'] : nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.step_ids(wizard_id)
|
|
||||||
steps = self.steps(wizard_id)
|
|
||||||
return [] if !steps
|
|
||||||
steps.map { |s| s['id'] }.flatten.uniq
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.field_ids(wizard_id, step_id)
|
|
||||||
steps = self.steps(wizard_id)
|
|
||||||
return [] if !steps
|
|
||||||
step = steps.select { |s| s['id'] === step_id }.first
|
|
||||||
if step && fields = step['fields']
|
|
||||||
fields.map { |f| f['id'] }
|
|
||||||
else
|
|
||||||
[]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.add_wizard(obj)
|
|
||||||
wizard = obj.is_a?(String) ? ::JSON.parse(json) : obj
|
|
||||||
PluginStore.set('custom_wizard', wizard["id"], wizard)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.find(wizard_id)
|
|
||||||
PluginStore.get('custom_wizard', wizard_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.list(user=nil)
|
|
||||||
PluginStoreRow.where(plugin_name: 'custom_wizard').order(:id)
|
|
||||||
.reduce([]) do |result, record|
|
|
||||||
attrs = JSON.parse(record.value)
|
|
||||||
|
|
||||||
if attrs.present? &&
|
|
||||||
attrs.is_a?(Hash) &&
|
|
||||||
attrs['id'].present? &&
|
|
||||||
attrs['name'].present?
|
|
||||||
|
|
||||||
result.push(self.new(attrs, user))
|
|
||||||
end
|
|
||||||
|
|
||||||
result
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.save(wizard)
|
|
||||||
existing_wizard = self.create(wizard[:id])
|
|
||||||
|
|
||||||
wizard[:steps].each do |step|
|
|
||||||
if step[:raw_description]
|
|
||||||
step[:description] = PrettyText.cook(step[:raw_description])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
wizard = wizard.slice!(:create)
|
|
||||||
|
|
||||||
ActiveRecord::Base.transaction do
|
|
||||||
PluginStore.set('custom_wizard', wizard[:id], wizard)
|
|
||||||
|
|
||||||
if wizard[:after_time]
|
|
||||||
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: wizard[:id])
|
|
||||||
enqueue_at = Time.parse(wizard[:after_time_scheduled]).utc
|
|
||||||
Jobs.enqueue_at(enqueue_at, :set_after_time_wizard, wizard_id: wizard[:id])
|
|
||||||
end
|
|
||||||
|
|
||||||
if existing_wizard && existing_wizard.after_time && !wizard[:after_time]
|
|
||||||
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: wizard[:id])
|
|
||||||
Jobs.enqueue(:clear_after_time_wizard, wizard_id: wizard[:id])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
wizard[:id]
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.remove(wizard_id)
|
|
||||||
wizard = self.create(wizard_id)
|
|
||||||
|
|
||||||
ActiveRecord::Base.transaction do
|
|
||||||
if wizard.after_time
|
|
||||||
Jobs.cancel_scheduled_job(:set_after_time_wizard)
|
|
||||||
Jobs.enqueue(:clear_after_time_wizard, wizard_id: wizard.id)
|
|
||||||
end
|
|
||||||
|
|
||||||
PluginStore.remove('custom_wizard', wizard.id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.exists?(wizard_id)
|
|
||||||
PluginStoreRow.exists?(plugin_name: 'custom_wizard', key: wizard_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.create(wizard_id, user = nil)
|
|
||||||
if wizard = self.find(wizard_id)
|
|
||||||
self.new(wizard.to_h, user)
|
|
||||||
else
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.set_submission_redirect(user, wizard_id, url)
|
def self.set_submission_redirect(user, wizard_id, url)
|
||||||
PluginStore.set("#{wizard_id.underscore}_submissions", user.id, [{ redirect_to: url }])
|
PluginStore.set("#{wizard_id.underscore}_submissions", user.id, [{ redirect_to: url }])
|
||||||
end
|
end
|
||||||
|
@ -364,12 +262,4 @@ class CustomWizard::Wizard
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.register_styles
|
|
||||||
full_path = "#{Rails.root}/plugins/discourse-custom-wizard/assets/stylesheets/wizard/wizard_custom.scss"
|
|
||||||
DiscoursePluginRegistry.register_asset(full_path, {}, "wizard_custom")
|
|
||||||
Stylesheet::Importer.register_import("wizard_custom") do
|
|
||||||
import_files(DiscoursePluginRegistry.stylesheets["wizard_custom"])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -55,6 +55,7 @@ after_initialize do
|
||||||
../lib/custom_wizard/mapper.rb
|
../lib/custom_wizard/mapper.rb
|
||||||
../lib/custom_wizard/log.rb
|
../lib/custom_wizard/log.rb
|
||||||
../lib/custom_wizard/step_updater.rb
|
../lib/custom_wizard/step_updater.rb
|
||||||
|
../lib/custom_wizard/template.rb
|
||||||
../lib/custom_wizard/validator.rb
|
../lib/custom_wizard/validator.rb
|
||||||
../lib/custom_wizard/wizard.rb
|
../lib/custom_wizard/wizard.rb
|
||||||
../lib/custom_wizard/api/api.rb
|
../lib/custom_wizard/api/api.rb
|
||||||
|
@ -158,7 +159,11 @@ after_initialize do
|
||||||
::Wizard::Field.prepend CustomWizardFieldExtension
|
::Wizard::Field.prepend CustomWizardFieldExtension
|
||||||
::Wizard::Step.prepend CustomWizardStepExtension
|
::Wizard::Step.prepend CustomWizardStepExtension
|
||||||
|
|
||||||
CustomWizard::Wizard.register_styles
|
full_path = "#{Rails.root}/plugins/discourse-custom-wizard/assets/stylesheets/wizard/wizard_custom.scss"
|
||||||
|
DiscoursePluginRegistry.register_asset(full_path, {}, "wizard_custom")
|
||||||
|
Stylesheet::Importer.register_import("wizard_custom") do
|
||||||
|
import_files(DiscoursePluginRegistry.stylesheets["wizard_custom"])
|
||||||
|
end
|
||||||
|
|
||||||
DiscourseEvent.trigger(:custom_wizard_ready)
|
DiscourseEvent.trigger(:custom_wizard_ready)
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,20 +7,23 @@ describe CustomWizard::Action do
|
||||||
|
|
||||||
before do
|
before do
|
||||||
Group.refresh_automatic_group!(:trust_level_2)
|
Group.refresh_automatic_group!(:trust_level_2)
|
||||||
template = JSON.parse(File.open(
|
CustomWizard::Template.add(
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
JSON.parse(File.open(
|
||||||
).read)
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
CustomWizard::Wizard.add_wizard(template)
|
).read)
|
||||||
@wizard = CustomWizard::Wizard.create('super_mega_fun_wizard', user)
|
)
|
||||||
|
@template = CustomWizard::Template.find('super_mega_fun_wizard')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates a topic' do
|
it 'creates a topic' do
|
||||||
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
updater = built_wizard.create_updater(built_wizard.steps[0].id,
|
|
||||||
|
updater = wizard.create_updater(
|
||||||
|
wizard.steps[0].id,
|
||||||
step_1_field_1: "Topic Title",
|
step_1_field_1: "Topic Title",
|
||||||
step_1_field_2: "topic body"
|
step_1_field_2: "topic body"
|
||||||
).update
|
).update
|
||||||
updater2 = built_wizard.create_updater(built_wizard.steps[1].id, {}).update
|
updater2 = wizard.create_updater(wizard.steps[1].id, {}).update
|
||||||
|
|
||||||
topic = Topic.where(title: "Topic Title")
|
topic = Topic.where(title: "Topic Title")
|
||||||
|
|
||||||
|
@ -34,9 +37,9 @@ describe CustomWizard::Action do
|
||||||
it 'sends a message' do
|
it 'sends a message' do
|
||||||
User.create(username: 'angus1', email: "angus1@email.com")
|
User.create(username: 'angus1', email: "angus1@email.com")
|
||||||
|
|
||||||
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
built_wizard.create_updater(built_wizard.steps[0].id, {}).update
|
wizard.create_updater(wizard.steps[0].id, {}).update
|
||||||
built_wizard.create_updater(built_wizard.steps[1].id, {}).update
|
wizard.create_updater(wizard.steps[1].id, {}).update
|
||||||
|
|
||||||
topic = Topic.where(
|
topic = Topic.where(
|
||||||
archetype: Archetype.private_message,
|
archetype: Archetype.private_message,
|
||||||
|
@ -54,26 +57,26 @@ describe CustomWizard::Action do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'updates a profile' do
|
it 'updates a profile' do
|
||||||
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
upload = Upload.create!(
|
upload = Upload.create!(
|
||||||
url: '/images/image.png',
|
url: '/images/image.png',
|
||||||
original_filename: 'image.png',
|
original_filename: 'image.png',
|
||||||
filesize: 100,
|
filesize: 100,
|
||||||
user_id: -1,
|
user_id: -1,
|
||||||
)
|
)
|
||||||
steps = built_wizard.steps
|
steps = wizard.steps
|
||||||
built_wizard.create_updater(steps[0].id, {}).update
|
wizard.create_updater(steps[0].id, {}).update
|
||||||
built_wizard.create_updater(steps[1].id,
|
wizard.create_updater(steps[1].id,
|
||||||
step_2_field_7: upload.as_json,
|
step_2_field_7: upload.as_json
|
||||||
).update
|
).update
|
||||||
expect(user.profile_background_upload.id).to eq(upload.id)
|
expect(user.profile_background_upload.id).to eq(upload.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'opens a composer' do
|
it 'opens a composer' do
|
||||||
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
built_wizard.create_updater(built_wizard.steps[0].id, step_1_field_1: "Text input").update
|
wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update
|
||||||
|
|
||||||
updater = built_wizard.create_updater(built_wizard.steps[1].id, {})
|
updater = wizard.create_updater(wizard.steps[1].id, {})
|
||||||
updater.update
|
updater.update
|
||||||
|
|
||||||
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
|
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
|
||||||
|
@ -85,34 +88,34 @@ describe CustomWizard::Action do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates a category' do
|
it 'creates a category' do
|
||||||
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
built_wizard.create_updater(built_wizard.steps[0].id, step_1_field_1: "Text input").update
|
wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update
|
||||||
built_wizard.create_updater(built_wizard.steps[1].id, {}).update
|
wizard.create_updater(wizard.steps[1].id, {}).update
|
||||||
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
|
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
|
||||||
expect(Category.where(id: submissions.first['action_8']).exists?).to eq(true)
|
expect(Category.where(id: submissions.first['action_8']).exists?).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'creates a group' do
|
it 'creates a group' do
|
||||||
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
step_id = built_wizard.steps[0].id
|
step_id = wizard.steps[0].id
|
||||||
updater = built_wizard.create_updater(step_id, step_1_field_1: "Text input").update
|
updater = wizard.create_updater(step_id, step_1_field_1: "Text input").update
|
||||||
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
|
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
|
||||||
expect(Group.where(name: submissions.first['action_9']).exists?).to eq(true)
|
expect(Group.where(name: submissions.first['action_9']).exists?).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'adds a user to a group' do
|
it 'adds a user to a group' do
|
||||||
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
step_id = built_wizard.steps[0].id
|
step_id = wizard.steps[0].id
|
||||||
updater = built_wizard.create_updater(step_id, step_1_field_1: "Text input").update
|
updater = wizard.create_updater(step_id, step_1_field_1: "Text input").update
|
||||||
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
|
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
|
||||||
group = Group.find_by(name: submissions.first['action_9'])
|
group = Group.find_by(name: submissions.first['action_9'])
|
||||||
expect(group.users.first.username).to eq('angus')
|
expect(group.users.first.username).to eq('angus')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'watches categories' do
|
it 'watches categories' do
|
||||||
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
built_wizard.create_updater(built_wizard.steps[0].id, step_1_field_1: "Text input").update
|
wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update
|
||||||
built_wizard.create_updater(built_wizard.steps[1].id, {}).update
|
wizard.create_updater(wizard.steps[1].id, {}).update
|
||||||
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
|
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
|
||||||
expect(CategoryUser.where(
|
expect(CategoryUser.where(
|
||||||
category_id: submissions.first['action_8'],
|
category_id: submissions.first['action_8'],
|
||||||
|
@ -125,8 +128,8 @@ describe CustomWizard::Action do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 're-routes a user' do
|
it 're-routes a user' do
|
||||||
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
updater = built_wizard.create_updater(built_wizard.steps.last.id, {})
|
updater = wizard.create_updater(wizard.steps.last.id, {})
|
||||||
updater.update
|
updater.update
|
||||||
expect(updater.result[:redirect_on_complete]).to eq("https://google.com")
|
expect(updater.result[:redirect_on_complete]).to eq("https://google.com")
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,19 +3,45 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
describe CustomWizard::Builder do
|
describe CustomWizard::Builder do
|
||||||
fab!(:user) { Fabricate(:user, username: 'angus', email: "angus@email.com", trust_level: TrustLevel[2]) }
|
fab!(:trusted_user) {
|
||||||
fab!(:new_user) { Fabricate(:user, trust_level: 0) }
|
Fabricate(
|
||||||
|
:user,
|
||||||
|
username: 'angus',
|
||||||
|
email: "angus@email.com",
|
||||||
|
trust_level: TrustLevel[3]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fab!(:user) { Fabricate(:user) }
|
||||||
fab!(:category1) { Fabricate(:category, name: 'cat1') }
|
fab!(:category1) { Fabricate(:category, name: 'cat1') }
|
||||||
fab!(:category2) { Fabricate(:category, name: 'cat2') }
|
fab!(:category2) { Fabricate(:category, name: 'cat2') }
|
||||||
fab!(:group) { Fabricate(:group) }
|
fab!(:group) { Fabricate(:group) }
|
||||||
|
|
||||||
before do
|
let(:required_data_json) {
|
||||||
Group.refresh_automatic_group!(:trust_level_2)
|
JSON.parse(File.open(
|
||||||
template = JSON.parse(File.open(
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/required_data.json"
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
|
||||||
).read)
|
).read)
|
||||||
CustomWizard::Wizard.add_wizard(template)
|
}
|
||||||
@wizard = CustomWizard::Wizard.create('super_mega_fun_wizard', user)
|
|
||||||
|
let(:permitted_json) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/permitted.json"
|
||||||
|
).read)
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:permitted_param_json) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/step/permitted_params.json"
|
||||||
|
).read)
|
||||||
|
}
|
||||||
|
|
||||||
|
before do
|
||||||
|
Group.refresh_automatic_group!(:trust_level_3)
|
||||||
|
CustomWizard::Template.add(
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
|
).read)
|
||||||
|
)
|
||||||
|
@template = CustomWizard::Template.find('super_mega_fun_wizard')
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'disabled' do
|
context 'disabled' do
|
||||||
|
@ -24,7 +50,9 @@ describe CustomWizard::Builder do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns nil" do
|
it "returns nil" do
|
||||||
expect(CustomWizard::Builder.new(@wizard.id, user).build).to eq(nil)
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
).to eq(nil)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -33,150 +61,276 @@ describe CustomWizard::Builder do
|
||||||
SiteSetting.custom_wizard_enabled = true
|
SiteSetting.custom_wizard_enabled = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "returns wizard metadata" do
|
||||||
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
expect(wizard.id).to eq("super_mega_fun_wizard")
|
||||||
|
expect(wizard.name).to eq("Super Mega Fun Wizard")
|
||||||
|
expect(wizard.background).to eq("#333333")
|
||||||
|
end
|
||||||
|
|
||||||
it "returns steps" do
|
it "returns steps" do
|
||||||
expect(
|
expect(
|
||||||
CustomWizard::Builder.new(@wizard.id, user).build.steps.length
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
).to eq(2)
|
.steps.length
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns no steps if multiple submissions are disabled and user has completed' do
|
|
||||||
wizard_template = CustomWizard::Wizard.find(@wizard.id)
|
|
||||||
wizard_template[:multiple_submissions] = false
|
|
||||||
CustomWizard::Wizard.save(wizard_template)
|
|
||||||
|
|
||||||
history_params = {
|
|
||||||
action: UserHistory.actions[:custom_wizard_step],
|
|
||||||
acting_user_id: user.id,
|
|
||||||
context: @wizard.id
|
|
||||||
}
|
|
||||||
@wizard.steps.each do |step|
|
|
||||||
UserHistory.create!(history_params.merge(subject: step.id))
|
|
||||||
end
|
|
||||||
|
|
||||||
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
|
|
||||||
expect(
|
|
||||||
CustomWizard::Builder.new(@wizard.id, user).build.steps.length
|
|
||||||
).to eq(0)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns no steps if user is not permitted' do
|
|
||||||
expect(
|
|
||||||
CustomWizard::Builder.new(@wizard.id, new_user).build.steps.length
|
|
||||||
).to eq(0)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns steps if user is permitted' do
|
|
||||||
expect(
|
|
||||||
CustomWizard::Builder.new(@wizard.id, user).build.steps.length
|
|
||||||
).to eq(3)
|
).to eq(3)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns a wizard with prefilled data if user has partially completed it' do
|
context "with multiple submissions disabled" do
|
||||||
expect(
|
before do
|
||||||
CustomWizard::Builder.new(@wizard.id, user)
|
@template[:multiple_submissions] = false
|
||||||
.build
|
CustomWizard::Template.save(@template.as_json)
|
||||||
.steps[0].fields[0].value
|
|
||||||
).to eq('I am prefilled')
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns a wizard with no prefilled data if options include reset' do
|
|
||||||
PluginStore.set("super_mega_fun_wizard_submissions", user.id, {
|
|
||||||
text: 'Input into text',
|
|
||||||
})
|
|
||||||
expect(
|
|
||||||
CustomWizard::Builder.new(@wizard.id, user)
|
|
||||||
.build(reset: true)
|
|
||||||
.steps[0].fields[0].value
|
|
||||||
).to eq(nil)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'building steps' do
|
|
||||||
it 'returns step metadata' do
|
|
||||||
expect(
|
|
||||||
CustomWizard::Builder.new(@wizard.id, user)
|
|
||||||
.build(reset: true)
|
|
||||||
.steps[0]
|
|
||||||
).to eq('Super Mega Fun Wizard')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'saves permitted params' do
|
it 'returns steps if user has not completed it' do
|
||||||
@wizard.steps[0].permitted_params = permitted_params
|
expect(
|
||||||
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build({}, param_key: 'param_value')
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
|
.steps.length
|
||||||
expect(submissions[0]['submission_param_key']).to eq('param_value')
|
).to eq(3)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'is not permitted if required data is not present' do
|
it 'returns no steps if user has completed it' do
|
||||||
@wizard.steps[0].required_data = required_data
|
@template[:steps].each do |step|
|
||||||
|
UserHistory.create!(
|
||||||
|
{
|
||||||
|
action: UserHistory.actions[:custom_wizard_step],
|
||||||
|
acting_user_id: user.id,
|
||||||
|
context: @template[:id]
|
||||||
|
}.merge(
|
||||||
|
subject: step[:id]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
CustomWizard::Builder.new(@wizard.id, user).build.steps[0].permitted
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.steps.length
|
||||||
|
).to eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with restricted permissions" do
|
||||||
|
before do
|
||||||
|
@template[:permitted] = permitted_json["permitted"]
|
||||||
|
CustomWizard::Template.save(@template.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is not permitted if user is not in permitted group' do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.permitted?
|
||||||
).to eq(false)
|
).to eq(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'it shows required data message if required data has message' do
|
it 'user cannot access if not permitted' do
|
||||||
@wizard.steps[0].required_data = required_data
|
expect(
|
||||||
@wizard.steps[0].required_data_message = "Data is required"
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
PluginStore.set("super_mega_fun_wizard_submissions", user.id,
|
.can_access?
|
||||||
text: 'Input into text',
|
).to eq(false)
|
||||||
)
|
|
||||||
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
|
|
||||||
expect(built_wizard.steps[0].permitted).to eq(false)
|
|
||||||
expect(built_wizard.steps[0].permitted_message).to eq("Data is required")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'is permitted if required data is present' do
|
it 'returns wizard metadata if user is not permitted' do
|
||||||
@wizard.steps[0].required_data = required_data
|
|
||||||
PluginStore.set('super_mega_fun_wizard_submissions', user.id,
|
|
||||||
text: "Input into text"
|
|
||||||
)
|
|
||||||
expect(
|
expect(
|
||||||
CustomWizard::Builder.new(@wizard.id, user).build.steps[0].permitted
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.name
|
||||||
|
).to eq("Super Mega Fun Wizard")
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns no steps if user is not permitted' do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.steps.length
|
||||||
|
).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is permitted if user is in permitted group' do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], trusted_user).build
|
||||||
|
.permitted?
|
||||||
).to eq(true)
|
).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns field metadata' do
|
it 'user can access if permitted' do
|
||||||
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
|
expect(
|
||||||
expect(built_wizard.steps[0].fields[0].label).to eq("<p>Name</p>")
|
CustomWizard::Builder.new(@template[:id], trusted_user).build
|
||||||
expect(built_wizard.steps[0].fields[0].type).to eq("text")
|
.can_access?
|
||||||
|
).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns fields' do
|
it 'returns steps if user is permitted' do
|
||||||
@wizard.steps[0].fields[1] = checkbox_field
|
expect(
|
||||||
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
|
CustomWizard::Builder.new(@template[:id], trusted_user).build
|
||||||
expect(built_wizard.steps[0].fields.length).to eq(2)
|
.steps.length
|
||||||
|
).to eq(3)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns prefilled data' do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.steps.first
|
||||||
|
.fields.first
|
||||||
|
.value
|
||||||
|
).to eq('I am prefilled')
|
||||||
|
end
|
||||||
|
|
||||||
|
context "user has partially completed" do
|
||||||
|
before do
|
||||||
|
PluginStore.set("super_mega_fun_wizard_submissions", user.id,
|
||||||
|
step_1_field_1: 'I am a user submission'
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns saved submissions' do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.steps.first
|
||||||
|
.fields.first
|
||||||
|
.value
|
||||||
|
).to eq('I am a user submission')
|
||||||
|
end
|
||||||
|
|
||||||
|
context "restart is enabled" do
|
||||||
|
before do
|
||||||
|
@template[:restart_on_revisit] = true
|
||||||
|
CustomWizard::Template.save(@template.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not return saved submissions' do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.steps.first
|
||||||
|
.fields.first
|
||||||
|
.value
|
||||||
|
).to eq('I am prefilled')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'building step' do
|
||||||
|
it 'returns step metadata' do
|
||||||
|
first_step = CustomWizard::Builder.new(@template[:id], user)
|
||||||
|
.build(reset: true)
|
||||||
|
.steps.first
|
||||||
|
|
||||||
|
expect(first_step.id).to eq("step_1")
|
||||||
|
expect(first_step.title).to eq("Text")
|
||||||
|
expect(first_step.description).to eq("<p>Text inputs!</p>")
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with required data' do
|
||||||
|
before do
|
||||||
|
@template[:steps][0][:required_data] = required_data_json['required_data']
|
||||||
|
@template[:steps][0][:required_data_message] = required_data_json['required_data_message']
|
||||||
|
CustomWizard::Template.save(@template.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is not permitted if required data is not present' do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.steps.first
|
||||||
|
.permitted
|
||||||
|
).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'it shows required data message' do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.steps.first
|
||||||
|
.permitted_message
|
||||||
|
).to eq("Missing required data")
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is permitted if required data is present' do
|
||||||
|
PluginStore.set('super_mega_fun_wizard_submissions', user.id,
|
||||||
|
required_data: "required_value"
|
||||||
|
)
|
||||||
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.steps.first
|
||||||
|
.permitted
|
||||||
|
).to eq(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with permitted params" do
|
||||||
|
before do
|
||||||
|
@template[:steps][0][:permitted_params] = permitted_param_json['permitted_params']
|
||||||
|
CustomWizard::Template.save(@template.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'saves permitted params' do
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build({},
|
||||||
|
param: 'param_value'
|
||||||
|
)
|
||||||
|
expect(
|
||||||
|
PluginStore.get("super_mega_fun_wizard_submissions", user.id)
|
||||||
|
.first['saved_param']
|
||||||
|
).to eq('param_value')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'building field' do
|
||||||
|
it 'returns field metadata' do
|
||||||
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
field = wizard.steps.first.fields.first
|
||||||
|
|
||||||
|
expect(field.label).to eq("<p>Text</p>")
|
||||||
|
expect(field.type).to eq("text")
|
||||||
|
expect(field.id).to eq("step_1_field_1")
|
||||||
|
expect(field.min_length).to eq("3")
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns all step fields' do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user)
|
||||||
|
.build
|
||||||
|
.steps.first
|
||||||
|
.fields.length
|
||||||
|
).to eq(4)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'on update' do
|
context 'on update' do
|
||||||
|
def perform_update(step_id, submission)
|
||||||
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
updater = wizard.create_updater(step_id, submission)
|
||||||
|
updater.update
|
||||||
|
updater
|
||||||
|
end
|
||||||
|
|
||||||
it 'saves submissions' do
|
it 'saves submissions' do
|
||||||
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
|
perform_update('step_1', step_1_field_1: 'Text input')
|
||||||
built_wizard.create_updater(built_wizard.steps[0].id,
|
|
||||||
step_1_field_1: 'Text input'
|
|
||||||
).update
|
|
||||||
expect(
|
expect(
|
||||||
PluginStore.get("super_mega_fun_wizard_submissions", user.id)
|
PluginStore.get("super_mega_fun_wizard_submissions", user.id)
|
||||||
.first['step_1_field_1']
|
.first['step_1_field_1']
|
||||||
).to eq('Text input')
|
).to eq('Text input')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'save submissions disabled' do
|
||||||
|
before do
|
||||||
|
@template[:save_submissions] = false
|
||||||
|
CustomWizard::Template.save(@template.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not save submissions" do
|
||||||
|
perform_update('step_1', step_1_field_1: 'Text input')
|
||||||
|
expect(
|
||||||
|
PluginStore.get("super_mega_fun_wizard_submissions", user.id)
|
||||||
|
).to eq(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'validation' do
|
context 'validation' do
|
||||||
it 'applies min length' do
|
it 'applies min length' do
|
||||||
@wizard.steps[0].fields[0].min_length = 10
|
expect(
|
||||||
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
|
perform_update('step_1', step_1_field_1: 'Te')
|
||||||
updater = built_wizard.create_updater(built_wizard.steps[0].id,
|
.errors.messages[:step_1_field_1].first
|
||||||
step_1_field_1: 'Te'
|
).to eq(I18n.t('wizard.field.too_short', label: 'Text', min: 3))
|
||||||
).update
|
|
||||||
expect(updater.errors.messages[:text].first).to eq(
|
|
||||||
I18n.t('wizard.field.too_short', label: 'Text', min: 3)
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'standardises boolean entries' do
|
it 'standardises boolean entries' do
|
||||||
@wizard.steps[0].fields[0] = checkbox_field
|
perform_update('step_2', step_2_field_5: 'false')
|
||||||
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
|
|
||||||
updater = built_wizard.create_updater(built_wizard.steps[1].id,
|
|
||||||
step_2_field_5: 'false'
|
|
||||||
).update
|
|
||||||
expect(
|
expect(
|
||||||
PluginStore.get("super_mega_fun_wizard_submissions", user.id)
|
PluginStore.get("super_mega_fun_wizard_submissions", user.id)
|
||||||
.first['step_2_field_5']
|
.first['step_2_field_5']
|
||||||
|
@ -184,12 +338,13 @@ describe CustomWizard::Builder do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'requires required fields' do
|
it 'requires required fields' do
|
||||||
@wizard.steps[0].fields[0]['required'] = true
|
@template[:steps][0][:fields][1][:required] = true
|
||||||
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
|
CustomWizard::Template.save(@template.as_json)
|
||||||
updater = built_wizard.create_updater(built_wizard.steps.second.id).update
|
|
||||||
expect(
|
expect(
|
||||||
updater.errors.messages[:step_1_field_1].first
|
perform_update('step_1', step_1_field_2: nil)
|
||||||
).to eq(I18n.t('wizard.field.required', label: 'Text'))
|
.errors.messages[:step_1_field_2].first
|
||||||
|
).to eq(I18n.t('wizard.field.required', label: 'Textarea'))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
17
spec/fixtures/step/permitted_params.json
gevendort
Normale Datei
17
spec/fixtures/step/permitted_params.json
gevendort
Normale Datei
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"permitted_params": [
|
||||||
|
{
|
||||||
|
"type": "association",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "param",
|
||||||
|
"key_type": "text",
|
||||||
|
"value": "saved_param",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "association"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
10
spec/fixtures/wizard.json
gevendort
10
spec/fixtures/wizard.json
gevendort
|
@ -7,16 +7,6 @@
|
||||||
"after_signup": false,
|
"after_signup": false,
|
||||||
"prompt_completion": true,
|
"prompt_completion": true,
|
||||||
"theme_id": 2,
|
"theme_id": 2,
|
||||||
"permitted": [
|
|
||||||
{
|
|
||||||
"type": "assignment",
|
|
||||||
"output_type": "group",
|
|
||||||
"output_connector": "set",
|
|
||||||
"output": [
|
|
||||||
12
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"steps": [
|
"steps": [
|
||||||
{
|
{
|
||||||
"id": "step_1",
|
"id": "step_1",
|
||||||
|
|
12
spec/fixtures/wizard/permitted.json
gevendort
Normale Datei
12
spec/fixtures/wizard/permitted.json
gevendort
Normale Datei
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"permitted": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output_type": "group",
|
||||||
|
"output_connector": "set",
|
||||||
|
"output": [
|
||||||
|
13
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
18
spec/fixtures/wizard/required_data.json
gevendort
Normale Datei
18
spec/fixtures/wizard/required_data.json
gevendort
Normale Datei
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"required_data_message": "Missing required data",
|
||||||
|
"required_data": [
|
||||||
|
{
|
||||||
|
"type": "validation",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "required_data",
|
||||||
|
"key_type": "text",
|
||||||
|
"value": "required_value",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "equal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ describe CustomWizard::WizardSerializer do
|
||||||
template = JSON.parse(File.open(
|
template = JSON.parse(File.open(
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
).read)
|
).read)
|
||||||
CustomWizard::Wizard.add_wizard(template)
|
CustomWizard::Template.add(template)
|
||||||
@wizard = CustomWizard::Wizard.create('super_mega_fun_wizard', user)
|
@wizard = CustomWizard::Wizard.create('super_mega_fun_wizard', user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Laden …
In neuem Issue referenzieren