1
0
Fork 0

working builder and action specs

Dieser Commit ist enthalten in:
Angus McLeod 2020-10-31 18:05:50 +11:00
Ursprung 8fdd263d8e
Commit b726d40a0c
15 geänderte Dateien mit 603 neuen und 393 gelöschten Zeilen

Datei anzeigen

@ -4,7 +4,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
def index
render_json_dump(
wizard_list: ActiveModel::ArraySerializer.new(
CustomWizard::Wizard.list,
CustomWizard::Template.list,
each_serializer: CustomWizard::BasicWizardSerializer
),
field_types: CustomWizard::Field.types
@ -14,7 +14,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
def show
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
else
render json: { none: true }
@ -22,8 +22,11 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
end
def remove
CustomWizard::Wizard.remove(@wizard.id)
if CustomWizard::Template.remove(@wizard.id)
render json: success_json
else
render json: failed_json
end
end
def save
@ -36,7 +39,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
if validation[:error]
render json: { error: validation[:error] }
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)
else
render json: failed_json

Datei anzeigen

@ -1,19 +1,30 @@
class CustomWizard::StepsController < ::ApplicationController
before_action :ensure_logged_in
before_action :ensure_can_update
def update
params.require(:step_id)
params.require(:wizard_id)
field_ids = CustomWizard::Wizard.field_ids(params[:wizard_id], params[:step_id])
permitted = params.permit(:wizard_id, :step_id)
if params[:fields]
permitted[:fields] = params[:fields].select { |k, v| field_ids.include? k }
permitted.permit!
wizard = @builder.build
step = wizard.steps.select { |s| s.id == update_params[:step_id] }.first
if !step || step.fields.blank?
raise Discourse::InvalidParameters.new(:step_id)
end
wizard = CustomWizard::Builder.new(permitted[:wizard_id].underscore, current_user).build
updater = wizard.create_updater(permitted[:step_id], permitted[:fields])
field_ids = step.fields.map(&:id)
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
if updater.success?
@ -29,4 +40,25 @@ class CustomWizard::StepsController < ::ApplicationController
render json: { errors: errors }, status: 422
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

Datei anzeigen

@ -24,7 +24,7 @@ class CustomWizard::WizardController < ::ApplicationController
if builder.wizard.present?
builder_opts = {}
builder_opts[:reset] = params[:reset] || builder.wizard.restart_on_revisit
builder_opts[:reset] = params[:reset]
built_wizard = builder.build(builder_opts, params)
render_serialized(built_wizard, ::CustomWizard::WizardSerializer, root: false)

Datei anzeigen

@ -2,13 +2,13 @@ class CustomWizard::Builder
attr_accessor :wizard, :updater, :submissions
def initialize(wizard_id, user=nil)
params = CustomWizard::Wizard.find(wizard_id)
return nil if params.blank?
template = CustomWizard::Template.find(wizard_id)
return nil if template.blank?
@wizard = CustomWizard::Wizard.new(params, user)
@steps = params['steps'] || []
@actions = params['actions'] || []
@submissions = @wizard.submissions if user && @wizard
@wizard = CustomWizard::Wizard.new(template, user)
@steps = template['steps'] || []
@actions = template['actions'] || []
@submissions = @wizard.submissions
end
def self.sorted_handlers
@ -48,12 +48,27 @@ class CustomWizard::Builder
return nil if !SiteSetting.custom_wizard_enabled || !@wizard
return @wizard if !@wizard.can_access?
build_opts[:reset] = build_opts[:reset] || @wizard.restart_on_revisit
reset_submissions if build_opts[:reset]
@steps.each do |step_template|
@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.banner = step_template['banner'] if step_template['banner']
step.key = step_template['key'] if step_template['key']
if step_template['description']
step.description = mapper.interpolate(
@ -63,59 +78,8 @@ class CustomWizard::Builder
)
end
step.key = step_template['key'] if step_template['key']
step.permitted = true
if permitted_params = step_template['permitted_params']
permitted_data = {}
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
save_permitted_params(permitted_params, params)
end
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[:image] = field_template['image'] if field_template['image']
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
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']]
end
params[:value] = prefill_field(field_template, step_template) || params[:value]
if field_template['type'] === 'group' && params[:value].present?
params[:value] = params[:value].first
end
@ -404,4 +368,44 @@ class CustomWizard::Builder
PluginStore.set("#{@wizard.id}_submissions", @wizard.user.id, @submissions)
@wizard.reset
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

Datei anzeigen

@ -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

Datei anzeigen

@ -95,7 +95,7 @@ class CustomWizard::Validator
end
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 = {
type: 'conflict',
params: { type: type, property: 'id', value: object[:id] }

Datei anzeigen

@ -24,6 +24,7 @@ class CustomWizard::Wizard
:needs_categories,
:needs_groups,
:steps,
:step_ids,
:actions,
:user
@ -52,6 +53,7 @@ class CustomWizard::Wizard
end
@first_step = nil
@step_ids = attrs['steps'].map { |s| s['id'] }
@steps = []
@actions = []
end
@ -65,13 +67,11 @@ class CustomWizard::Wizard
yield step if block_given?
last_step = @steps.last
last_step = steps.last
steps << step
@steps << step
# If it's the first step
if @steps.size == 1
@first_step = step
if steps.size == 1
first_step = step
step.index = 0
elsif last_step.present?
last_step.next = step
@ -81,67 +81,62 @@ class CustomWizard::Wizard
end
def start
return nil if !@user
return nil if !user
if unfinished? && last_completed_step = ::UserHistory.where(
acting_user_id: @user.id,
acting_user_id: user.id,
action: ::UserHistory.actions[:custom_wizard_step],
context: @id,
subject: @steps.map(&:id)
context: id,
subject: steps.map(&:id)
).order("created_at").last
step_id = last_completed_step.subject
last_index = @steps.index { |s| s.id == step_id }
@steps[last_index + 1]
last_index = steps.index { |s| s.id == step_id }
steps[last_index + 1]
else
@first_step
first_step
end
end
def create_updater(step_id, fields)
step = @steps.find { |s| s.id == step_id }
wizard = self
CustomWizard::StepUpdater.new(@user, wizard, step, fields)
CustomWizard::StepUpdater.new(user, wizard, step, fields)
end
def unfinished?
return nil if !@user
return nil if !user
most_recent = ::UserHistory.where(
acting_user_id: @user.id,
acting_user_id: user.id,
action: ::UserHistory.actions[:custom_wizard_step],
context: @id,
context: id,
).distinct.order('updated_at DESC').first
if most_recent && most_recent.subject == "reset"
false
elsif most_recent
last_finished_step = most_recent.subject
last_step = CustomWizard::Wizard.step_ids(@id).last
last_finished_step != last_step
most_recent.subject != steps.last.id
else
true
end
end
def completed?
return nil if !@user
steps = CustomWizard::Wizard.step_ids(@id)
return nil if !user
history = ::UserHistory.where(
acting_user_id: @user.id,
acting_user_id: user.id,
action: ::UserHistory.actions[:custom_wizard_step],
context: @id
context: id
)
if @after_time
history = history.where("updated_at > ?", @after_time_scheduled)
if after_time
history = history.where("updated_at > ?", after_time_scheduled)
end
completed = history.distinct.order(:subject).pluck(:subject)
(steps - completed).empty?
(step_ids - completed).empty?
end
def permitted?
@ -178,33 +173,38 @@ class CustomWizard::Wizard
def reset
::UserHistory.create(
action: ::UserHistory.actions[:custom_wizard_step],
acting_user_id: @user.id,
context: @id,
acting_user_id: user.id,
context: id,
subject: "reset"
)
end
def categories
@categories ||= ::Site.new(Guardian.new(@user)).categories
@categories ||= ::Site.new(Guardian.new(user)).categories
end
def groups
@groups ||= ::Site.new(Guardian.new(@user)).groups
@groups ||= ::Site.new(Guardian.new(user)).groups
end
def submissions
Array.wrap(PluginStore.get("#{id}_submissions", @user.id))
Array.wrap(PluginStore.get("#{id}_submissions", user.id))
end
def self.filter_records(filter)
PluginStoreRow.where("
plugin_name = 'custom_wizard' AND
(value::json ->> '#{filter}')::boolean IS TRUE
")
def self.create(wizard_id, user = nil)
if template = CustomWizard::Template.find(wizard_id)
self.new(template.to_h, user)
else
false
end
end
def self.list(user=nil)
CustomWizard::Template.list.map { |template| self.new(template.to_h, user) }
end
def self.after_signup(user)
if (records = filter_records('after_signup')).any?
if (records = CustomWizard::Template.setting_enabled('after_signup')).any?
result = false
records
@ -225,9 +225,9 @@ class CustomWizard::Wizard
end
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|
wizard = CustomWizard::Wizard.new(::JSON.parse(record.value), user)
wizard = self.new(::JSON.parse(record.value), user)
if wizard.permitted? && !wizard.completed?
result.push(id: wizard.id, name: wizard.name)
@ -241,115 +241,13 @@ class CustomWizard::Wizard
end
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
else
false
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)
PluginStore.set("#{wizard_id.underscore}_submissions", user.id, [{ redirect_to: url }])
end
@ -364,12 +262,4 @@ class CustomWizard::Wizard
false
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

Datei anzeigen

@ -55,6 +55,7 @@ after_initialize do
../lib/custom_wizard/mapper.rb
../lib/custom_wizard/log.rb
../lib/custom_wizard/step_updater.rb
../lib/custom_wizard/template.rb
../lib/custom_wizard/validator.rb
../lib/custom_wizard/wizard.rb
../lib/custom_wizard/api/api.rb
@ -158,7 +159,11 @@ after_initialize do
::Wizard::Field.prepend CustomWizardFieldExtension
::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)
end

Datei anzeigen

@ -7,20 +7,23 @@ describe CustomWizard::Action do
before do
Group.refresh_automatic_group!(:trust_level_2)
template = JSON.parse(File.open(
CustomWizard::Template.add(
JSON.parse(File.open(
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
).read)
CustomWizard::Wizard.add_wizard(template)
@wizard = CustomWizard::Wizard.create('super_mega_fun_wizard', user)
)
@template = CustomWizard::Template.find('super_mega_fun_wizard')
end
it 'creates a topic' do
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
updater = built_wizard.create_updater(built_wizard.steps[0].id,
wizard = CustomWizard::Builder.new(@template[:id], user).build
updater = wizard.create_updater(
wizard.steps[0].id,
step_1_field_1: "Topic Title",
step_1_field_2: "topic body"
).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")
@ -34,9 +37,9 @@ describe CustomWizard::Action do
it 'sends a message' do
User.create(username: 'angus1', email: "angus1@email.com")
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
built_wizard.create_updater(built_wizard.steps[0].id, {}).update
built_wizard.create_updater(built_wizard.steps[1].id, {}).update
wizard = CustomWizard::Builder.new(@template[:id], user).build
wizard.create_updater(wizard.steps[0].id, {}).update
wizard.create_updater(wizard.steps[1].id, {}).update
topic = Topic.where(
archetype: Archetype.private_message,
@ -54,26 +57,26 @@ describe CustomWizard::Action do
end
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!(
url: '/images/image.png',
original_filename: 'image.png',
filesize: 100,
user_id: -1,
)
steps = built_wizard.steps
built_wizard.create_updater(steps[0].id, {}).update
built_wizard.create_updater(steps[1].id,
step_2_field_7: upload.as_json,
steps = wizard.steps
wizard.create_updater(steps[0].id, {}).update
wizard.create_updater(steps[1].id,
step_2_field_7: upload.as_json
).update
expect(user.profile_background_upload.id).to eq(upload.id)
end
it 'opens a composer' do
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
built_wizard.create_updater(built_wizard.steps[0].id, step_1_field_1: "Text input").update
wizard = CustomWizard::Builder.new(@template[:id], user).build
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
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
@ -85,34 +88,34 @@ describe CustomWizard::Action do
end
it 'creates a category' do
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
built_wizard.create_updater(built_wizard.steps[0].id, step_1_field_1: "Text input").update
built_wizard.create_updater(built_wizard.steps[1].id, {}).update
wizard = CustomWizard::Builder.new(@template[:id], user).build
wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update
wizard.create_updater(wizard.steps[1].id, {}).update
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
expect(Category.where(id: submissions.first['action_8']).exists?).to eq(true)
end
it 'creates a group' do
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
step_id = built_wizard.steps[0].id
updater = built_wizard.create_updater(step_id, step_1_field_1: "Text input").update
wizard = CustomWizard::Builder.new(@template[:id], user).build
step_id = wizard.steps[0].id
updater = wizard.create_updater(step_id, step_1_field_1: "Text input").update
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
expect(Group.where(name: submissions.first['action_9']).exists?).to eq(true)
end
it 'adds a user to a group' do
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
step_id = built_wizard.steps[0].id
updater = built_wizard.create_updater(step_id, step_1_field_1: "Text input").update
wizard = CustomWizard::Builder.new(@template[:id], user).build
step_id = wizard.steps[0].id
updater = wizard.create_updater(step_id, step_1_field_1: "Text input").update
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
group = Group.find_by(name: submissions.first['action_9'])
expect(group.users.first.username).to eq('angus')
end
it 'watches categories' do
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
built_wizard.create_updater(built_wizard.steps[0].id, step_1_field_1: "Text input").update
built_wizard.create_updater(built_wizard.steps[1].id, {}).update
wizard = CustomWizard::Builder.new(@template[:id], user).build
wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update
wizard.create_updater(wizard.steps[1].id, {}).update
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
expect(CategoryUser.where(
category_id: submissions.first['action_8'],
@ -125,8 +128,8 @@ describe CustomWizard::Action do
end
it 're-routes a user' do
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
updater = built_wizard.create_updater(built_wizard.steps.last.id, {})
wizard = CustomWizard::Builder.new(@template[:id], user).build
updater = wizard.create_updater(wizard.steps.last.id, {})
updater.update
expect(updater.result[:redirect_on_complete]).to eq("https://google.com")
end

Datei anzeigen

@ -3,19 +3,45 @@
require 'rails_helper'
describe CustomWizard::Builder do
fab!(:user) { Fabricate(:user, username: 'angus', email: "angus@email.com", trust_level: TrustLevel[2]) }
fab!(:new_user) { Fabricate(:user, trust_level: 0) }
fab!(:trusted_user) {
Fabricate(
:user,
username: 'angus',
email: "angus@email.com",
trust_level: TrustLevel[3]
)
}
fab!(:user) { Fabricate(:user) }
fab!(:category1) { Fabricate(:category, name: 'cat1') }
fab!(:category2) { Fabricate(:category, name: 'cat2') }
fab!(:group) { Fabricate(:group) }
let(:required_data_json) {
JSON.parse(File.open(
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/required_data.json"
).read)
}
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_2)
template = JSON.parse(File.open(
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)
CustomWizard::Wizard.add_wizard(template)
@wizard = CustomWizard::Wizard.create('super_mega_fun_wizard', user)
)
@template = CustomWizard::Template.find('super_mega_fun_wizard')
end
context 'disabled' do
@ -24,7 +50,9 @@ describe CustomWizard::Builder do
end
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
@ -33,150 +61,276 @@ describe CustomWizard::Builder do
SiteSetting.custom_wizard_enabled = true
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
expect(
CustomWizard::Builder.new(@wizard.id, user).build.steps.length
).to eq(2)
CustomWizard::Builder.new(@template[:id], user).build
.steps.length
).to eq(3)
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)
context "with multiple submissions disabled" do
before do
@template[:multiple_submissions] = false
CustomWizard::Template.save(@template.as_json)
end
history_params = {
it 'returns steps if user has not completed it' do
expect(
CustomWizard::Builder.new(@template[:id], user).build
.steps.length
).to eq(3)
end
it 'returns no steps if user has completed it' do
@template[:steps].each do |step|
UserHistory.create!(
{
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))
context: @template[:id]
}.merge(
subject: step[:id]
)
)
end
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
expect(
CustomWizard::Builder.new(@wizard.id, user).build.steps.length
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)
end
it 'user cannot access if not permitted' do
expect(
CustomWizard::Builder.new(@template[:id], user).build
.can_access?
).to eq(false)
end
it 'returns wizard metadata if user is not permitted' do
expect(
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(@wizard.id, new_user).build.steps.length
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)
end
it 'user can access if permitted' do
expect(
CustomWizard::Builder.new(@template[:id], trusted_user).build
.can_access?
).to eq(true)
end
it 'returns steps if user is permitted' do
expect(
CustomWizard::Builder.new(@wizard.id, user).build.steps.length
CustomWizard::Builder.new(@template[:id], trusted_user).build
.steps.length
).to eq(3)
end
end
it 'returns a wizard with prefilled data if user has partially completed it' do
it 'returns prefilled data' do
expect(
CustomWizard::Builder.new(@wizard.id, user)
.build
.steps[0].fields[0].value
CustomWizard::Builder.new(@template[:id], user).build
.steps.first
.fields.first
.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)
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
context 'building steps' do
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
expect(
CustomWizard::Builder.new(@wizard.id, user)
first_step = CustomWizard::Builder.new(@template[:id], user)
.build(reset: true)
.steps[0]
).to eq('Super Mega Fun Wizard')
.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
it 'saves permitted params' do
@wizard.steps[0].permitted_params = permitted_params
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build({}, param_key: 'param_value')
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
expect(submissions[0]['submission_param_key']).to eq('param_value')
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
@wizard.steps[0].required_data = required_data
expect(
CustomWizard::Builder.new(@wizard.id, user).build.steps[0].permitted
CustomWizard::Builder.new(@template[:id], user).build
.steps.first
.permitted
).to eq(false)
end
it 'it shows required data message if required data has message' do
@wizard.steps[0].required_data = required_data
@wizard.steps[0].required_data_message = "Data is required"
PluginStore.set("super_mega_fun_wizard_submissions", user.id,
text: 'Input into text',
)
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")
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
@wizard.steps[0].required_data = required_data
PluginStore.set('super_mega_fun_wizard_submissions', user.id,
text: "Input into text"
required_data: "required_value"
)
expect(
CustomWizard::Builder.new(@wizard.id, user).build.steps[0].permitted
CustomWizard::Builder.new(@template[:id], user).build
.steps.first
.permitted
).to eq(true)
end
it 'returns field metadata' do
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
expect(built_wizard.steps[0].fields[0].label).to eq("<p>Name</p>")
expect(built_wizard.steps[0].fields[0].type).to eq("text")
end
it 'returns fields' do
@wizard.steps[0].fields[1] = checkbox_field
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
expect(built_wizard.steps[0].fields.length).to eq(2)
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
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
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
built_wizard.create_updater(built_wizard.steps[0].id,
step_1_field_1: 'Text input'
).update
perform_update('step_1', step_1_field_1: 'Text input')
expect(
PluginStore.get("super_mega_fun_wizard_submissions", user.id)
.first['step_1_field_1']
).to eq('Text input')
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
it 'applies min length' do
@wizard.steps[0].fields[0].min_length = 10
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
updater = built_wizard.create_updater(built_wizard.steps[0].id,
step_1_field_1: 'Te'
).update
expect(updater.errors.messages[:text].first).to eq(
I18n.t('wizard.field.too_short', label: 'Text', min: 3)
)
expect(
perform_update('step_1', step_1_field_1: 'Te')
.errors.messages[:step_1_field_1].first
).to eq(I18n.t('wizard.field.too_short', label: 'Text', min: 3))
end
it 'standardises boolean entries' do
@wizard.steps[0].fields[0] = checkbox_field
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
perform_update('step_2', step_2_field_5: 'false')
expect(
PluginStore.get("super_mega_fun_wizard_submissions", user.id)
.first['step_2_field_5']
@ -184,12 +338,13 @@ describe CustomWizard::Builder do
end
it 'requires required fields' do
@wizard.steps[0].fields[0]['required'] = true
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
updater = built_wizard.create_updater(built_wizard.steps.second.id).update
@template[:steps][0][:fields][1][:required] = true
CustomWizard::Template.save(@template.as_json)
expect(
updater.errors.messages[:step_1_field_1].first
).to eq(I18n.t('wizard.field.required', label: 'Text'))
perform_update('step_1', step_1_field_2: nil)
.errors.messages[:step_1_field_2].first
).to eq(I18n.t('wizard.field.required', label: 'Textarea'))
end
end
end

17
spec/fixtures/step/permitted_params.json gevendort Normale Datei
Datei anzeigen

@ -0,0 +1,17 @@
{
"permitted_params": [
{
"type": "association",
"pairs": [
{
"index": 0,
"key": "param",
"key_type": "text",
"value": "saved_param",
"value_type": "text",
"connector": "association"
}
]
}
]
}

Datei anzeigen

@ -7,16 +7,6 @@
"after_signup": false,
"prompt_completion": true,
"theme_id": 2,
"permitted": [
{
"type": "assignment",
"output_type": "group",
"output_connector": "set",
"output": [
12
]
}
],
"steps": [
{
"id": "step_1",

12
spec/fixtures/wizard/permitted.json gevendort Normale Datei
Datei anzeigen

@ -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
Datei anzeigen

@ -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"
}
]
}
]
}

Datei anzeigen

@ -10,7 +10,7 @@ describe CustomWizard::WizardSerializer do
template = JSON.parse(File.open(
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
).read)
CustomWizard::Wizard.add_wizard(template)
CustomWizard::Template.add(template)
@wizard = CustomWizard::Wizard.create('super_mega_fun_wizard', user)
end