Merge pull request #58 from paviliondev/tests_improvements
Rspec Suite
Dieser Commit ist enthalten in:
Commit
017ac37743
60 geänderte Dateien mit 3245 neuen und 805 gelöschten Zeilen
|
@ -1,12 +1,10 @@
|
||||||
# We want to use the KVM-based system, so require sudo
|
|
||||||
sudo: required
|
|
||||||
services:
|
services:
|
||||||
- docker
|
- docker
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- git clone --depth=1 https://github.com/discourse/discourse-plugin-ci
|
- git clone --depth=1 https://github.com/discourse/discourse-plugin-ci
|
||||||
|
|
||||||
install: true # Prevent travis doing bundle install
|
install: true
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- discourse-plugin-ci/script.sh
|
- discourse-plugin-ci/script.sh
|
||||||
|
|
|
@ -113,6 +113,7 @@
|
||||||
wizardFieldSelection=true
|
wizardFieldSelection=true
|
||||||
userFieldSelection='key,value'
|
userFieldSelection='key,value'
|
||||||
categorySelection='output'
|
categorySelection='output'
|
||||||
|
wizardActionSelection='output'
|
||||||
outputDefaultSelection='category'
|
outputDefaultSelection='category'
|
||||||
context='action'
|
context='action'
|
||||||
)}}
|
)}}
|
||||||
|
@ -198,6 +199,7 @@
|
||||||
textSelection='value'
|
textSelection='value'
|
||||||
userFieldSelection='key'
|
userFieldSelection='key'
|
||||||
wizardFieldSelection='value'
|
wizardFieldSelection='value'
|
||||||
|
wizardActionSelection='value'
|
||||||
keyDefaultSelection='userField'
|
keyDefaultSelection='userField'
|
||||||
context='action'
|
context='action'
|
||||||
)}}
|
)}}
|
||||||
|
@ -270,6 +272,7 @@
|
||||||
textSelection='value,output'
|
textSelection='value,output'
|
||||||
wizardFieldSelection='key,value,assignment'
|
wizardFieldSelection='key,value,assignment'
|
||||||
userFieldSelection='key,value,assignment'
|
userFieldSelection='key,value,assignment'
|
||||||
|
wizardActionSelection=true
|
||||||
groupSelection='value,output'
|
groupSelection='value,output'
|
||||||
outputDefaultSelection='group'
|
outputDefaultSelection='group'
|
||||||
context='action'
|
context='action'
|
||||||
|
|
|
@ -26,6 +26,11 @@ en:
|
||||||
file_large: "File too large"
|
file_large: "File too large"
|
||||||
invalid_json: "File is not a valid json file"
|
invalid_json: "File is not a valid json file"
|
||||||
no_valid_wizards: "File doesn't contain any valid wizards"
|
no_valid_wizards: "File doesn't contain any valid wizards"
|
||||||
|
|
||||||
|
validation:
|
||||||
|
required: "%{property} is required"
|
||||||
|
conflict: "Wizard with %{wizard_id} already exists"
|
||||||
|
after_time: "After time setting is invalid"
|
||||||
|
|
||||||
site_settings:
|
site_settings:
|
||||||
custom_wizard_enabled: "Enable custom wizards."
|
custom_wizard_enabled: "Enable custom wizards."
|
||||||
|
|
|
@ -36,8 +36,8 @@ Discourse::Application.routes.append do
|
||||||
|
|
||||||
get 'admin/wizards/logs' => 'admin_logs#index'
|
get 'admin/wizards/logs' => 'admin_logs#index'
|
||||||
|
|
||||||
get 'admin/wizards/transfer' => 'transfer#index'
|
get 'admin/wizards/transfer' => 'admin_transfer#index'
|
||||||
get 'admin/wizards/transfer/export' => 'transfer#export'
|
get 'admin/wizards/transfer/export' => 'admin_transfer#export'
|
||||||
post 'admin/wizards/transfer/import' => 'transfer#import'
|
post 'admin/wizards/transfer/import' => 'admin_transfer#import'
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -9,6 +9,7 @@ class CustomWizard::AdminController < ::Admin::AdminController
|
||||||
def find_wizard
|
def find_wizard
|
||||||
params.require(:wizard_id)
|
params.require(:wizard_id)
|
||||||
@wizard = CustomWizard::Wizard.create(params[:wizard_id].underscore)
|
@wizard = CustomWizard::Wizard.create(params[:wizard_id].underscore)
|
||||||
|
raise Discourse::InvalidParameters.new(:wizard_id) unless @wizard
|
||||||
end
|
end
|
||||||
|
|
||||||
def custom_field_list
|
def custom_field_list
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
class CustomWizard::AdminLogsController < CustomWizard::AdminController
|
class CustomWizard::AdminLogsController < CustomWizard::AdminController
|
||||||
def index
|
def index
|
||||||
render_serialized(
|
render_serialized(
|
||||||
CustomWizard::Log.list(params[:page].to_i),
|
CustomWizard::Log.list(params[:page].to_i, params[:limit].to_i),
|
||||||
CustomWizard::LogSerializer
|
CustomWizard::LogSerializer
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,29 +1,23 @@
|
||||||
class CustomWizard::AdminSubmissionsController < CustomWizard::AdminController
|
class CustomWizard::AdminSubmissionsController < CustomWizard::AdminController
|
||||||
skip_before_action :preload_json, :check_xhr, only: [:download]
|
skip_before_action :preload_json, :check_xhr, only: [:download]
|
||||||
|
before_action :find_wizard, except: [:index]
|
||||||
before_action :find_wizard
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
render json: ActiveModel::ArraySerializer.new(
|
render json: ActiveModel::ArraySerializer.new(
|
||||||
CustomWizard::Wizard.list,
|
CustomWizard::Wizard.list(current_user),
|
||||||
each_serializer: CustomWizard::BasicWizardSerializer
|
each_serializer: CustomWizard::BasicWizardSerializer
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
result = {}
|
render_json_dump(
|
||||||
|
wizard: CustomWizard::BasicWizardSerializer.new(@wizard, root: false),
|
||||||
if wizard = @wizard
|
submissions: build_submissions.as_json
|
||||||
submissions = build_submissions(wizard.id)
|
)
|
||||||
result[:wizard] = CustomWizard::BasicWizardSerializer.new(wizard, root: false)
|
|
||||||
result[:submissions] = submissions.as_json
|
|
||||||
end
|
|
||||||
|
|
||||||
render_json_dump(result)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def download
|
def download
|
||||||
send_data build_submissions(@wizard.id).to_json,
|
send_data build_submissions.to_json,
|
||||||
filename: "#{Discourse.current_hostname}-wizard-submissions-#{@wizard.name}.json",
|
filename: "#{Discourse.current_hostname}-wizard-submissions-#{@wizard.name}.json",
|
||||||
content_type: "application/json",
|
content_type: "application/json",
|
||||||
disposition: "attachment"
|
disposition: "attachment"
|
||||||
|
@ -31,23 +25,21 @@ class CustomWizard::AdminSubmissionsController < CustomWizard::AdminController
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def build_submissions(wizard_id)
|
def build_submissions
|
||||||
rows = PluginStoreRow.where(plugin_name: "#{wizard_id}_submissions").order('id DESC')
|
PluginStoreRow.where(plugin_name: "#{@wizard.id}_submissions")
|
||||||
|
.order('id DESC')
|
||||||
submissions = [*rows].map do |row|
|
.map do |row|
|
||||||
value = ::JSON.parse(row.value)
|
value = ::JSON.parse(row.value)
|
||||||
|
|
||||||
if user = User.find_by(id: row.key)
|
if user = User.find_by(id: row.key)
|
||||||
username = user.username
|
username = user.username
|
||||||
else
|
else
|
||||||
username = I18n.t('admin.wizard.submissions.no_user', id: row.key)
|
username = I18n.t('admin.wizard.submissions.no_user', id: row.key)
|
||||||
end
|
end
|
||||||
|
|
||||||
value.map do |submission|
|
value.map do |v|
|
||||||
{
|
{ username: username }.merge!(v.except("redirect_to"))
|
||||||
username: username
|
end
|
||||||
}.merge!(submission.except("redirect_to"))
|
end.flatten
|
||||||
end
|
|
||||||
end.flatten
|
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -1,25 +1,22 @@
|
||||||
class CustomWizard::TransferController < ::ApplicationController
|
class CustomWizard::AdminTransferController < CustomWizard::AdminController
|
||||||
before_action :ensure_logged_in
|
|
||||||
before_action :ensure_admin
|
|
||||||
skip_before_action :check_xhr, :only => [:export]
|
skip_before_action :check_xhr, :only => [:export]
|
||||||
|
|
||||||
def index
|
|
||||||
end
|
|
||||||
|
|
||||||
def export
|
def export
|
||||||
wizards = params['wizards']
|
wizard_ids = params['wizards']
|
||||||
wizard_objects = []
|
templates = []
|
||||||
|
|
||||||
if wizards.nil?
|
if wizard_ids.nil?
|
||||||
render json: { error: I18n.t('wizard.export.error.select_one') }
|
render json: { error: I18n.t('wizard.export.error.select_one') }
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
wizards.each do |w|
|
wizard_ids.each do |wizard_id|
|
||||||
wizard_objects.push(PluginStore.get('custom_wizard', w.tr('-', '_')))
|
if template = CustomWizard::Template.find(wizard_id)
|
||||||
|
templates.push(template)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
send_data wizard_objects.to_json,
|
send_data templates.to_json,
|
||||||
type: "application/json",
|
type: "application/json",
|
||||||
disposition: 'attachment',
|
disposition: 'attachment',
|
||||||
filename: 'wizards.json'
|
filename: 'wizards.json'
|
||||||
|
@ -27,45 +24,42 @@ class CustomWizard::TransferController < ::ApplicationController
|
||||||
|
|
||||||
def import
|
def import
|
||||||
file = File.read(params['file'].tempfile)
|
file = File.read(params['file'].tempfile)
|
||||||
|
|
||||||
if file.nil?
|
if file.nil?
|
||||||
render json: { error: I18n.t('wizard.import.error.no_file') }
|
render json: { error: I18n.t('wizard.import.error.no_file') }
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
fileSize = file.size
|
file_size = file.size
|
||||||
maxFileSize = 512 * 1024
|
max_file_size = 512 * 1024
|
||||||
|
|
||||||
if maxFileSize < fileSize
|
if max_file_size < file_size
|
||||||
render json: { error: I18n.t('wizard.import.error.file_large') }
|
render json: { error: I18n.t('wizard.import.error.file_large') }
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
begin
|
begin
|
||||||
jsonObject = JSON.parse file
|
template_json = JSON.parse file
|
||||||
rescue JSON::ParserError
|
rescue JSON::ParserError
|
||||||
render json: { error: I18n.t('wizard.import.error.invalid_json') }
|
render json: { error: I18n.t('wizard.import.error.invalid_json') }
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
countValid = 0
|
|
||||||
success_ids = []
|
success_ids = []
|
||||||
failed_ids = []
|
failed_ids = []
|
||||||
|
|
||||||
jsonObject.each do |o|
|
template_json.each do |t_json|
|
||||||
if !CustomWizard::Wizard.new(o)
|
template = CustomWizard::Template.new(t_json)
|
||||||
failed_ids.push o['id']
|
template.save(skip_jobs: true)
|
||||||
next
|
|
||||||
|
if template.errors.any?
|
||||||
|
failed_ids.push t_json['id']
|
||||||
|
else
|
||||||
|
success_ids.push t_json['id']
|
||||||
end
|
end
|
||||||
|
|
||||||
countValid += 1
|
|
||||||
pluginStoreEntry = PluginStore.new 'custom_wizard'
|
|
||||||
saved = pluginStoreEntry.set(o['id'], o) unless pluginStoreEntry.get(o['id'])
|
|
||||||
success_ids.push o['id'] if !!saved
|
|
||||||
failed_ids.push o['id'] if !saved
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if countValid == 0
|
if success_ids.length == 0
|
||||||
render json: { error: I18n.t('wizard.import.error.no_valid_wizards') }
|
render json: { error: I18n.t('wizard.import.error.no_valid_wizards') }
|
||||||
else
|
else
|
||||||
render json: { success: success_ids, failed: failed_ids }
|
render json: { success: success_ids, failed: failed_ids }
|
|
@ -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::Wizard.list(current_user),
|
||||||
each_serializer: CustomWizard::BasicWizardSerializer
|
each_serializer: CustomWizard::BasicWizardSerializer
|
||||||
),
|
),
|
||||||
field_types: CustomWizard::Field.types,
|
field_types: CustomWizard::Field.types,
|
||||||
|
@ -15,7 +15,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 }
|
||||||
|
@ -23,25 +23,21 @@ 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
|
||||||
opts = {}
|
template = CustomWizard::Template.new(save_wizard_params.to_h)
|
||||||
opts[:create] = params[:create] if params[:create]
|
wizard_id = template.save(create: params[:create])
|
||||||
|
|
||||||
validator = CustomWizard::Validator.new(save_wizard_params.to_h, opts)
|
if template.errors.any?
|
||||||
validation = validator.perform
|
render json: failed_json.merge(errors: result.errors.full_messages)
|
||||||
|
|
||||||
if validation[:error]
|
|
||||||
render json: { error: validation[:error] }
|
|
||||||
else
|
else
|
||||||
if wizard_id = CustomWizard::Wizard.save(validation[:wizard])
|
render json: success_json.merge(wizard_id: wizard_id)
|
||||||
render json: success_json.merge(wizard_id: wizard_id)
|
|
||||||
else
|
|
||||||
render json: failed_json
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,38 @@
|
||||||
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])
|
|
||||||
|
wizard = @builder.build
|
||||||
|
step = wizard.steps.select { |s| s.id == update_params[:step_id] }.first
|
||||||
|
|
||||||
permitted = params.permit(:wizard_id, :step_id)
|
if !step || step.fields.blank?
|
||||||
if params[:fields]
|
raise Discourse::InvalidParameters.new(:step_id)
|
||||||
permitted[:fields] = params[:fields].select { |k, v| field_ids.include? k }
|
|
||||||
permitted.permit!
|
|
||||||
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])
|
|
||||||
|
update = update_params.to_h
|
||||||
|
|
||||||
|
if params[:fields]
|
||||||
|
update[:fields] = {}
|
||||||
|
|
||||||
|
params[:fields].each do |k, v|
|
||||||
|
update[:fields][k] = v if field_ids.include? k
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
updater = wizard.create_updater(update[:step_id], update[:fields])
|
||||||
updater.update
|
updater.update
|
||||||
|
|
||||||
if updater.success?
|
if updater.success?
|
||||||
result = success_json
|
result = success_json
|
||||||
result.merge!(updater.result) if updater.result
|
result.merge!(updater.result) if updater.result
|
||||||
result[:refresh_required] = true if updater.refresh_required?
|
result[:refresh_required] = true if updater.refresh_required?
|
||||||
|
|
||||||
render json: result
|
render json: result
|
||||||
else
|
else
|
||||||
errors = []
|
errors = []
|
||||||
|
@ -29,4 +42,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
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
class CustomWizard::WizardController < ::ApplicationController
|
class CustomWizard::WizardController < ::ApplicationController
|
||||||
prepend_view_path(Rails.root.join('plugins', 'discourse-custom-wizard', 'views'))
|
prepend_view_path(Rails.root.join('plugins', 'discourse-custom-wizard', 'views'))
|
||||||
layout 'wizard'
|
layout 'wizard'
|
||||||
|
|
||||||
|
before_action :ensure_plugin_enabled
|
||||||
helper_method :wizard_page_title
|
helper_method :wizard_page_title
|
||||||
helper_method :theme_ids
|
helper_method :theme_ids
|
||||||
|
|
||||||
|
@ -24,7 +25,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)
|
||||||
|
@ -38,7 +39,7 @@ class CustomWizard::WizardController < ::ApplicationController
|
||||||
|
|
||||||
def skip
|
def skip
|
||||||
params.require(:wizard_id)
|
params.require(:wizard_id)
|
||||||
|
|
||||||
if wizard.required && !wizard.completed? && wizard.permitted?
|
if wizard.required && !wizard.completed? && wizard.permitted?
|
||||||
return render json: { error: I18n.t('wizard.no_skip') }
|
return render json: { error: I18n.t('wizard.no_skip') }
|
||||||
end
|
end
|
||||||
|
@ -47,16 +48,11 @@ class CustomWizard::WizardController < ::ApplicationController
|
||||||
user = current_user
|
user = current_user
|
||||||
|
|
||||||
if user
|
if user
|
||||||
submission = wizard.submissions.last
|
submission = wizard.current_submission
|
||||||
|
|
||||||
if submission && submission['redirect_to']
|
if submission && submission['redirect_to']
|
||||||
result.merge!(redirect_to: submission['redirect_to'])
|
result.merge!(redirect_to: submission['redirect_to'])
|
||||||
end
|
end
|
||||||
|
|
||||||
if submission && !wizard.save_submissions
|
|
||||||
PluginStore.remove("#{wizard.id}_submissions", user.id)
|
|
||||||
end
|
|
||||||
|
|
||||||
if user.custom_fields['redirect_to_wizard'] === wizard.id
|
if user.custom_fields['redirect_to_wizard'] === wizard.id
|
||||||
user.custom_fields.delete('redirect_to_wizard')
|
user.custom_fields.delete('redirect_to_wizard')
|
||||||
user.save_custom_fields(true)
|
user.save_custom_fields(true)
|
||||||
|
@ -65,4 +61,12 @@ class CustomWizard::WizardController < ::ApplicationController
|
||||||
|
|
||||||
render json: result
|
render json: result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def ensure_plugin_enabled
|
||||||
|
unless SiteSetting.custom_wizard_enabled
|
||||||
|
redirect_to path("/")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,7 @@ module Jobs
|
||||||
def execute(args)
|
def execute(args)
|
||||||
if SiteSetting.custom_wizard_enabled
|
if SiteSetting.custom_wizard_enabled
|
||||||
wizard = CustomWizard::Wizard.create(args[:wizard_id])
|
wizard = CustomWizard::Wizard.create(args[:wizard_id])
|
||||||
|
|
||||||
if wizard && wizard.after_time
|
if wizard && wizard.after_time
|
||||||
user_ids = []
|
user_ids = []
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,11 @@ class CustomWizard::Action
|
||||||
multiple: true
|
multiple: true
|
||||||
).perform
|
).perform
|
||||||
|
|
||||||
|
if targets.blank?
|
||||||
|
log_error("no recipients", "send_message has no recipients")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
targets.each do |target|
|
targets.each do |target|
|
||||||
if Group.find_by(name: target)
|
if Group.find_by(name: target)
|
||||||
params[:target_group_names] = target
|
params[:target_group_names] = target
|
||||||
|
@ -125,12 +130,18 @@ class CustomWizard::Action
|
||||||
|
|
||||||
def update_profile
|
def update_profile
|
||||||
params = {}
|
params = {}
|
||||||
|
|
||||||
if (profile_updates = action['profile_updates'])
|
if (profile_updates = action['profile_updates'])
|
||||||
profile_updates.first[:pairs].each do |pair|
|
profile_updates.first[:pairs].each do |pair|
|
||||||
if allowed_profile_field?(pair['key'])
|
if allowed_profile_field?(pair['key'])
|
||||||
key = cast_profile_key(pair['key'])
|
key = cast_profile_key(pair['key'])
|
||||||
value = cast_profile_value(mapper.map_field(pair['value'], pair['value_type']), pair['key'])
|
value = cast_profile_value(
|
||||||
|
mapper.map_field(
|
||||||
|
pair['value'],
|
||||||
|
pair['value_type']
|
||||||
|
),
|
||||||
|
pair['key']
|
||||||
|
)
|
||||||
|
|
||||||
if user_field?(pair['key'])
|
if user_field?(pair['key'])
|
||||||
params[:custom_fields] ||= {}
|
params[:custom_fields] ||= {}
|
||||||
|
@ -143,10 +154,10 @@ class CustomWizard::Action
|
||||||
end
|
end
|
||||||
|
|
||||||
params = add_custom_fields(params)
|
params = add_custom_fields(params)
|
||||||
|
|
||||||
if params.present?
|
if params.present?
|
||||||
result = UserUpdater.new(Discourse.system_user, user).update(params)
|
result = UserUpdater.new(Discourse.system_user, user).update(params)
|
||||||
|
|
||||||
if params[:avatar].present?
|
if params[:avatar].present?
|
||||||
result = update_avatar(params[:avatar])
|
result = update_avatar(params[:avatar])
|
||||||
end
|
end
|
||||||
|
@ -256,13 +267,13 @@ class CustomWizard::Action
|
||||||
|
|
||||||
def open_composer
|
def open_composer
|
||||||
params = basic_topic_params
|
params = basic_topic_params
|
||||||
|
|
||||||
if params[:title].present? && params[:raw].present?
|
if params[:title].present? && params[:raw].present?
|
||||||
url = "/new-topic?title=#{params[:title]}"
|
url = "/new-topic?title=#{params[:title]}"
|
||||||
url += "&body=#{params[:raw]}"
|
url += "&body=#{params[:raw]}"
|
||||||
|
|
||||||
if category_id = action_category
|
if category_id = action_category
|
||||||
if category_id && category = Category.find(category_id)
|
if category = Category.find_by(id: category_id)
|
||||||
url += "&category=#{category.full_slug('/')}"
|
url += "&category=#{category.full_slug('/')}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -272,7 +283,7 @@ class CustomWizard::Action
|
||||||
end
|
end
|
||||||
|
|
||||||
route_to = Discourse.base_uri + URI.encode(url)
|
route_to = Discourse.base_uri + URI.encode(url)
|
||||||
data['redirect_on_complete'] = route_to
|
data['route_to'] = route_to
|
||||||
|
|
||||||
log_info("route: #{route_to}")
|
log_info("route: #{route_to}")
|
||||||
else
|
else
|
||||||
|
@ -289,8 +300,15 @@ class CustomWizard::Action
|
||||||
multiple: true
|
multiple: true
|
||||||
}
|
}
|
||||||
).perform
|
).perform
|
||||||
|
|
||||||
|
group_map = group_map.flatten.compact
|
||||||
|
|
||||||
|
unless group_map.present?
|
||||||
|
log_error("invalid group map")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
groups = group_map.flatten.reduce([]) do |groups, g|
|
groups = group_map.reduce([]) do |groups, g|
|
||||||
begin
|
begin
|
||||||
groups.push(Integer(g))
|
groups.push(Integer(g))
|
||||||
rescue ArgumentError
|
rescue ArgumentError
|
||||||
|
@ -330,7 +348,7 @@ class CustomWizard::Action
|
||||||
user: user
|
user: user
|
||||||
).perform
|
).perform
|
||||||
end
|
end
|
||||||
|
|
||||||
if action['code']
|
if action['code']
|
||||||
data[action['code']] = SecureRandom.hex(8)
|
data[action['code']] = SecureRandom.hex(8)
|
||||||
url += "&#{action['code']}=#{data[action['code']]}"
|
url += "&#{action['code']}=#{data[action['code']]}"
|
||||||
|
@ -342,20 +360,36 @@ class CustomWizard::Action
|
||||||
log_info("route: #{route_to}")
|
log_info("route: #{route_to}")
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_group
|
def create_group
|
||||||
group =
|
group =
|
||||||
begin
|
begin
|
||||||
Group.new(new_group_params)
|
Group.new(new_group_params.except(:usernames, :owner_usernames))
|
||||||
rescue ArgumentError => e
|
rescue ArgumentError => e
|
||||||
raise Discourse::InvalidParameters, "Invalid group params"
|
raise Discourse::InvalidParameters, "Invalid group params"
|
||||||
end
|
end
|
||||||
|
|
||||||
if group.save
|
if group.save
|
||||||
GroupActionLogger.new(user, group).log_change_group_settings
|
def get_user_ids(username_string)
|
||||||
|
User.where(username: username_string.split(",")).pluck(:id)
|
||||||
|
end
|
||||||
|
|
||||||
|
if new_group_params[:owner_usernames].present?
|
||||||
|
owner_ids = get_user_ids(new_group_params[:owner_usernames])
|
||||||
|
owner_ids.each { |user_id| group.group_users.build(user_id: user_id, owner: true) }
|
||||||
|
end
|
||||||
|
|
||||||
|
if new_group_params[:usernames].present?
|
||||||
|
user_ids = get_user_ids(new_group_params[:usernames])
|
||||||
|
user_ids -= owner_ids if owner_ids
|
||||||
|
user_ids.each { |user_id| group.group_users.build(user_id: user_id) }
|
||||||
|
end
|
||||||
|
|
||||||
|
GroupActionLogger.new(user, group, skip_guardian: true).log_change_group_settings
|
||||||
log_success("Group created", group.name)
|
log_success("Group created", group.name)
|
||||||
|
|
||||||
result.output = group.name
|
result.output = group.name
|
||||||
else
|
else
|
||||||
log_error("Group creation failed")
|
log_error("Group creation failed", group.errors.messages)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -372,7 +406,7 @@ class CustomWizard::Action
|
||||||
log_success("Category created", category.name)
|
log_success("Category created", category.name)
|
||||||
result.output = category.id
|
result.output = category.id
|
||||||
else
|
else
|
||||||
log_error("Category creation failed")
|
log_error("Category creation failed", category.errors.messages)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -385,6 +419,8 @@ class CustomWizard::Action
|
||||||
user: user
|
user: user
|
||||||
).perform
|
).perform
|
||||||
|
|
||||||
|
return false unless output.present?
|
||||||
|
|
||||||
if output.is_a?(Array)
|
if output.is_a?(Array)
|
||||||
output.first
|
output.first
|
||||||
elsif output.is_a?(Integer)
|
elsif output.is_a?(Integer)
|
||||||
|
@ -400,6 +436,8 @@ class CustomWizard::Action
|
||||||
data: data,
|
data: data,
|
||||||
user: user,
|
user: user,
|
||||||
).perform
|
).perform
|
||||||
|
|
||||||
|
return false unless output.present?
|
||||||
|
|
||||||
if output.is_a?(Array)
|
if output.is_a?(Array)
|
||||||
output.flatten
|
output.flatten
|
||||||
|
@ -472,11 +510,11 @@ class CustomWizard::Action
|
||||||
def public_topic_params
|
def public_topic_params
|
||||||
params = {}
|
params = {}
|
||||||
|
|
||||||
if (category = action_category)
|
if category = action_category
|
||||||
params[:category] = category
|
params[:category] = category
|
||||||
end
|
end
|
||||||
|
|
||||||
if (tags = action_tags)
|
if tags = action_tags
|
||||||
params[:tags] = tags
|
params[:tags] = tags
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -528,10 +566,12 @@ class CustomWizard::Action
|
||||||
user: user
|
user: user
|
||||||
).perform
|
).perform
|
||||||
|
|
||||||
value = value.parameterize(separator: '_') if attr === "name"
|
if value
|
||||||
value = value.to_i if attr.include?("_level")
|
value = value.parameterize(separator: '_') if attr === "name"
|
||||||
|
value = value.to_i if attr.include?("_level")
|
||||||
params[attr.to_sym] = value
|
|
||||||
|
params[attr.to_sym] = value
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -556,30 +596,36 @@ class CustomWizard::Action
|
||||||
user: user
|
user: user
|
||||||
).perform
|
).perform
|
||||||
|
|
||||||
if attr === "parent_category_id" && value.is_a?(Array)
|
if value
|
||||||
value = value[0]
|
if attr === "parent_category_id" && value.is_a?(Array)
|
||||||
end
|
value = value[0]
|
||||||
|
|
||||||
if attr === "permissions" && value.is_a?(Array)
|
|
||||||
permissions = value
|
|
||||||
value = {}
|
|
||||||
|
|
||||||
permissions.each do |p|
|
|
||||||
k = p[:key]
|
|
||||||
v = p[:value].to_i
|
|
||||||
|
|
||||||
if k.is_a?(Array)
|
|
||||||
group = Group.find_by(id: k[0])
|
|
||||||
k = group.name
|
|
||||||
else
|
|
||||||
k = k.parameterize(separator: '_')
|
|
||||||
end
|
|
||||||
|
|
||||||
value[k] = v
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if attr === "permissions" && value.is_a?(Array)
|
||||||
|
permissions = value
|
||||||
|
value = {}
|
||||||
|
|
||||||
|
permissions.each do |p|
|
||||||
|
k = p[:key]
|
||||||
|
v = p[:value].to_i
|
||||||
|
|
||||||
|
if k.is_a?(Array)
|
||||||
|
group = Group.find_by(id: k[0])
|
||||||
|
k = group.name
|
||||||
|
else
|
||||||
|
k = k.parameterize(separator: '_')
|
||||||
|
end
|
||||||
|
|
||||||
|
value[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if attr === 'slug'
|
||||||
|
value = value.parameterize(separator: '-')
|
||||||
|
end
|
||||||
|
|
||||||
|
params[attr.to_sym] = value
|
||||||
end
|
end
|
||||||
|
|
||||||
params[attr.to_sym] = value
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -607,6 +653,8 @@ class CustomWizard::Action
|
||||||
end
|
end
|
||||||
|
|
||||||
def cast_profile_value(value, key)
|
def cast_profile_value(value, key)
|
||||||
|
return value if value.nil?
|
||||||
|
|
||||||
if profile_url_fields.include?(key)
|
if profile_url_fields.include?(key)
|
||||||
value['url']
|
value['url']
|
||||||
elsif key === 'avatar'
|
elsif key === 'avatar'
|
||||||
|
|
|
@ -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,26 @@ 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?
|
||||||
|
|
||||||
reset_submissions if build_opts[:reset]
|
build_opts[:reset] = build_opts[:reset] || @wizard.restart_on_revisit
|
||||||
|
|
||||||
@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 +77,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
|
||||||
|
@ -133,7 +96,7 @@ class CustomWizard::Builder
|
||||||
validate_field(field, updater, step_template) if field['type'] != 'text_only'
|
validate_field(field, updater, step_template) if field['type'] != 'text_only'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
next if updater.errors.any?
|
next if updater.errors.any?
|
||||||
|
|
||||||
CustomWizard::Builder.step_handlers.each do |handler|
|
CustomWizard::Builder.step_handlers.each do |handler|
|
||||||
|
@ -146,9 +109,7 @@ class CustomWizard::Builder
|
||||||
|
|
||||||
data = updater.fields
|
data = updater.fields
|
||||||
|
|
||||||
## if the wizard has data from the previous steps make that accessible to the actions.
|
if submission = @wizard.current_submission
|
||||||
if @submissions && @submissions.last && !@submissions.last.key?("submitted_at")
|
|
||||||
submission = @submissions.last
|
|
||||||
data = submission.merge(data)
|
data = submission.merge(data)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -156,10 +117,10 @@ class CustomWizard::Builder
|
||||||
|
|
||||||
if @actions.present?
|
if @actions.present?
|
||||||
@actions.each do |action|
|
@actions.each do |action|
|
||||||
|
|
||||||
if (action['run_after'] === updater.step.id) ||
|
if (action['run_after'] === updater.step.id) ||
|
||||||
(final_step && (!action['run_after'] || (action['run_after'] === 'wizard_completion')))
|
(final_step && (!action['run_after'] || (action['run_after'] === 'wizard_completion')))
|
||||||
|
|
||||||
CustomWizard::Action.new(
|
CustomWizard::Action.new(
|
||||||
wizard: @wizard,
|
wizard: @wizard,
|
||||||
action: action,
|
action: action,
|
||||||
|
@ -169,29 +130,31 @@ class CustomWizard::Builder
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if route_to = data['route_to']
|
|
||||||
data.delete('route_to')
|
|
||||||
end
|
|
||||||
|
|
||||||
if @wizard.save_submissions && updater.errors.empty?
|
|
||||||
save_submissions(data, final_step)
|
|
||||||
elsif final_step
|
|
||||||
PluginStore.remove("#{@wizard.id}_submissions", @wizard.user.id)
|
|
||||||
end
|
|
||||||
|
|
||||||
if final_step && @wizard.id === @wizard.user.custom_fields['redirect_to_wizard']
|
|
||||||
@wizard.user.custom_fields.delete('redirect_to_wizard');
|
|
||||||
@wizard.user.save_custom_fields(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
if updater.errors.empty?
|
if updater.errors.empty?
|
||||||
|
if route_to = data['route_to']
|
||||||
|
data.delete('route_to')
|
||||||
|
end
|
||||||
|
|
||||||
|
if @wizard.save_submissions
|
||||||
|
save_submissions(data, final_step)
|
||||||
|
end
|
||||||
|
|
||||||
if final_step
|
if final_step
|
||||||
|
if @wizard.id == @wizard.user.custom_fields['redirect_to_wizard']
|
||||||
|
@wizard.user.custom_fields.delete('redirect_to_wizard');
|
||||||
|
@wizard.user.save_custom_fields(true)
|
||||||
|
end
|
||||||
|
|
||||||
redirect_url = route_to || data['redirect_on_complete'] || data["redirect_to"]
|
redirect_url = route_to || data['redirect_on_complete'] || data["redirect_to"]
|
||||||
updater.result[:redirect_on_complete] = redirect_url
|
updater.result[:redirect_on_complete] = redirect_url
|
||||||
elsif route_to
|
elsif route_to
|
||||||
updater.result[:redirect_on_next] = route_to
|
updater.result[:redirect_on_next] = route_to
|
||||||
end
|
end
|
||||||
|
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -211,15 +174,13 @@ 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']
|
||||||
## Load previously submitted values
|
params[:value] = prefill_field(field_template, step_template)
|
||||||
if !build_opts[:reset] && @submissions.last && !@submissions.last.key?("submitted_at")
|
|
||||||
submission = @submissions.last
|
if !build_opts[:reset] && (submission = @wizard.current_submission)
|
||||||
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
|
||||||
|
@ -339,7 +300,7 @@ class CustomWizard::Builder
|
||||||
if type === 'time' && value.present? && !validate_time(value)
|
if type === 'time' && value.present? && !validate_time(value)
|
||||||
updater.errors.add(id, I18n.t('wizard.field.invalid_time'))
|
updater.errors.add(id, I18n.t('wizard.field.invalid_time'))
|
||||||
end
|
end
|
||||||
|
|
||||||
CustomWizard::Builder.field_validators.each do |validator|
|
CustomWizard::Builder.field_validators.each do |validator|
|
||||||
if type === validator[:type]
|
if type === validator[:type]
|
||||||
validator[:block].call(field, updater, step_template)
|
validator[:block].call(field, updater, step_template)
|
||||||
|
@ -395,13 +356,47 @@ class CustomWizard::Builder
|
||||||
if data.present?
|
if data.present?
|
||||||
@submissions.pop(1) if @wizard.unfinished?
|
@submissions.pop(1) if @wizard.unfinished?
|
||||||
@submissions.push(data)
|
@submissions.push(data)
|
||||||
PluginStore.set("#{@wizard.id}_submissions", @wizard.user.id, @submissions)
|
@wizard.set_submissions(@submissions)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def save_permitted_params(permitted_params, params)
|
||||||
|
permitted_data = {}
|
||||||
|
|
||||||
def reset_submissions
|
permitted_params.each do |pp|
|
||||||
@submissions.pop(1) if @wizard.unfinished?
|
pair = pp['pairs'].first
|
||||||
PluginStore.set("#{@wizard.id}_submissions", @wizard.user.id, @submissions)
|
params_key = pair['key'].to_sym
|
||||||
@wizard.reset
|
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
|
end
|
||||||
|
|
|
@ -57,10 +57,10 @@ class CustomWizard::Field
|
||||||
@require_assets ||= {}
|
@require_assets ||= {}
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.add_assets(type, plugin = nil, asset_paths = [], opts={})
|
def self.register(type, plugin = nil, asset_paths = [], opts={})
|
||||||
if type
|
if type
|
||||||
types[type] ||= {}
|
types[type.to_sym] ||= {}
|
||||||
types[type] = opts[:type_opts] if opts[:type_opts].present?
|
types[type.to_sym] = opts[:type_opts] if opts[:type_opts].present?
|
||||||
end
|
end
|
||||||
|
|
||||||
if plugin && asset_paths
|
if plugin && asset_paths
|
||||||
|
|
|
@ -29,9 +29,12 @@ class CustomWizard::Log
|
||||||
").order("value::json->>'date' DESC")
|
").order("value::json->>'date' DESC")
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.list(page = 0)
|
def self.list(page = 0, limit = nil)
|
||||||
self.list_query.limit(PAGE_LIMIT)
|
limit = limit.to_i > 0 ? limit.to_i : PAGE_LIMIT
|
||||||
.offset(page * PAGE_LIMIT)
|
page = page.to_i
|
||||||
|
|
||||||
|
self.list_query.limit(limit)
|
||||||
|
.offset(page * limit)
|
||||||
.map { |r| self.new(JSON.parse(r.value)) }
|
.map { |r| self.new(JSON.parse(r.value)) }
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -48,7 +48,7 @@ class CustomWizard::Mapper
|
||||||
inputs.each do |input|
|
inputs.each do |input|
|
||||||
input_type = input['type']
|
input_type = input['type']
|
||||||
pairs = input['pairs']
|
pairs = input['pairs']
|
||||||
|
|
||||||
if (input_type === 'conditional' && validate_pairs(pairs)) || input_type === 'assignment'
|
if (input_type === 'conditional' && validate_pairs(pairs)) || input_type === 'assignment'
|
||||||
output = input['output']
|
output = input['output']
|
||||||
output_type = input['output_type']
|
output_type = input['output_type']
|
||||||
|
@ -144,7 +144,7 @@ class CustomWizard::Mapper
|
||||||
end
|
end
|
||||||
|
|
||||||
if operator == '=~'
|
if operator == '=~'
|
||||||
result == 0 ? true : false
|
result.nil? ? false : true
|
||||||
else
|
else
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
115
lib/custom_wizard/template.rb
Normale Datei
115
lib/custom_wizard/template.rb
Normale Datei
|
@ -0,0 +1,115 @@
|
||||||
|
class CustomWizard::Template
|
||||||
|
include HasErrors
|
||||||
|
|
||||||
|
attr_reader :data,
|
||||||
|
:opts
|
||||||
|
|
||||||
|
def initialize(data)
|
||||||
|
@data = data
|
||||||
|
end
|
||||||
|
|
||||||
|
def save(opts={})
|
||||||
|
@opts = opts
|
||||||
|
|
||||||
|
normalize_data
|
||||||
|
validate_data
|
||||||
|
prepare_data
|
||||||
|
|
||||||
|
return false if errors.any?
|
||||||
|
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
schedule_save_jobs unless opts[:skip_jobs]
|
||||||
|
PluginStore.set('custom_wizard', @data[:id], @data)
|
||||||
|
end
|
||||||
|
|
||||||
|
@data[:id]
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.save(data, opts={})
|
||||||
|
new(data).save(opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.find(wizard_id)
|
||||||
|
PluginStore.get('custom_wizard', wizard_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.remove(wizard_id)
|
||||||
|
wizard = CustomWizard::Wizard.create(wizard_id)
|
||||||
|
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
PluginStore.remove('custom_wizard', wizard.id)
|
||||||
|
|
||||||
|
if wizard.after_time
|
||||||
|
Jobs.cancel_scheduled_job(:set_after_time_wizard)
|
||||||
|
Jobs.enqueue(:clear_after_time_wizard, wizard_id: wizard_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.exists?(wizard_id)
|
||||||
|
PluginStoreRow.exists?(plugin_name: 'custom_wizard', key: wizard_id)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.list(setting: nil, order: :id)
|
||||||
|
query = "plugin_name = 'custom_wizard'"
|
||||||
|
query += "AND (value::json ->> '#{setting}')::boolean IS TRUE" if setting
|
||||||
|
|
||||||
|
PluginStoreRow.where(query).order(order)
|
||||||
|
.reduce([]) do |result, record|
|
||||||
|
attrs = JSON.parse(record.value)
|
||||||
|
|
||||||
|
if attrs.present? &&
|
||||||
|
attrs.is_a?(Hash) &&
|
||||||
|
attrs['id'].present? &&
|
||||||
|
attrs['name'].present?
|
||||||
|
|
||||||
|
result.push(attrs)
|
||||||
|
end
|
||||||
|
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def normalize_data
|
||||||
|
@data = ::JSON.parse(@data) if @data.is_a?(String)
|
||||||
|
@data = @data.with_indifferent_access
|
||||||
|
end
|
||||||
|
|
||||||
|
def prepare_data
|
||||||
|
@data[:steps].each do |step|
|
||||||
|
if step[:raw_description]
|
||||||
|
step[:description] = PrettyText.cook(step[:raw_description])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate_data
|
||||||
|
validator = CustomWizard::Validator.new(@data, @opts)
|
||||||
|
validator.perform
|
||||||
|
add_errors_from(validator)
|
||||||
|
end
|
||||||
|
|
||||||
|
def schedule_save_jobs
|
||||||
|
if @data[:after_time] && @data[:after_time_scheduled]
|
||||||
|
wizard_id = @data[:id]
|
||||||
|
old_data = CustomWizard::Template.find(data[:id])
|
||||||
|
|
||||||
|
begin
|
||||||
|
enqueue_wizard_at = Time.parse(@data[:after_time_scheduled]).utc
|
||||||
|
rescue ArgumentError
|
||||||
|
errors.add :validation, I18n.t("wizard.validation.after_time")
|
||||||
|
raise ActiveRecord::Rollback.new
|
||||||
|
end
|
||||||
|
|
||||||
|
if enqueue_wizard_at
|
||||||
|
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: wizard_id)
|
||||||
|
Jobs.enqueue_at(enqueue_wizard_at, :set_after_time_wizard, wizard_id: wizard_id)
|
||||||
|
elsif old_data && old_data[:after_time]
|
||||||
|
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: wizard_id)
|
||||||
|
Jobs.enqueue(:clear_after_time_wizard, wizard_id: wizard_id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,52 +1,38 @@
|
||||||
class CustomWizard::Validator
|
class CustomWizard::Validator
|
||||||
|
include HasErrors
|
||||||
|
|
||||||
def initialize(params, opts={})
|
def initialize(data, opts={})
|
||||||
@params = params
|
@data = data
|
||||||
@opts = opts
|
@opts = opts
|
||||||
@error = nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def perform
|
def perform
|
||||||
params = @params
|
data = @data
|
||||||
|
|
||||||
check_id(params, :wizard)
|
check_id(data, :wizard)
|
||||||
check_required(params, :wizard)
|
check_required(data, :wizard)
|
||||||
check_depdendent(params, :wizard)
|
validate_after_time
|
||||||
|
|
||||||
after_time = nil
|
|
||||||
|
|
||||||
if !@error && @params[:after_time]
|
|
||||||
validate_after_time
|
|
||||||
end
|
|
||||||
|
|
||||||
if !@error
|
data[:steps].each do |step|
|
||||||
params[:steps].each do |step|
|
check_required(step, :step)
|
||||||
check_required(step, :step)
|
|
||||||
check_depdendent(step, :step)
|
|
||||||
break if @error.present?
|
|
||||||
|
|
||||||
if params[:fields].present?
|
|
||||||
params[:fields].each do |field|
|
|
||||||
check_required(field, :field)
|
|
||||||
check_depdendent(field, :field)
|
|
||||||
break if @error.present?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if params[:actions].present?
|
if data[:fields].present?
|
||||||
params[:actions].each do |action|
|
data[:fields].each do |field|
|
||||||
check_required(action, :action)
|
check_required(field, :field)
|
||||||
check_depdendent(action, :action)
|
|
||||||
break if @error.present?
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if data[:actions].present?
|
||||||
|
data[:actions].each do |action|
|
||||||
|
check_required(action, :action)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if @error
|
if errors.any?
|
||||||
{ error: @error }
|
false
|
||||||
else
|
else
|
||||||
{ wizard: params }
|
true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -59,54 +45,28 @@ class CustomWizard::Validator
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.dependent
|
|
||||||
{
|
|
||||||
wizard: {
|
|
||||||
after_time: 'after_time_scheduled'
|
|
||||||
},
|
|
||||||
step: {},
|
|
||||||
field: {},
|
|
||||||
action: {}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def check_required(object, type)
|
def check_required(object, type)
|
||||||
CustomWizard::Validator.required[type].each do |property|
|
CustomWizard::Validator.required[type].each do |property|
|
||||||
if object[property].blank?
|
if object[property].blank?
|
||||||
@error = {
|
errors.add :validation, I18n.t("wizard.validation.required", property: property)
|
||||||
type: 'required',
|
|
||||||
params: { type: type, property: property }
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def check_depdendent(object, type)
|
|
||||||
CustomWizard::Validator.dependent[type].each do |property, dependent|
|
|
||||||
if object[property] && object[dependent].blank?
|
|
||||||
@error = {
|
|
||||||
type: 'dependent',
|
|
||||||
params: { property: property, dependent: dependent }
|
|
||||||
}
|
|
||||||
end
|
|
||||||
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 = {
|
errors.add :validation, I18n.t("wizard.validation.conflict", id: object[:id])
|
||||||
type: 'conflict',
|
|
||||||
params: { type: type, property: 'id', value: object[:id] }
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_after_time
|
def validate_after_time
|
||||||
wizard = CustomWizard::Wizard.create(@params[:id]) if !@opts[:create]
|
return unless @data[:after_time]
|
||||||
|
|
||||||
|
wizard = CustomWizard::Wizard.create(@data[:id]) if !@opts[:create]
|
||||||
current_time = wizard.present? ? wizard.after_time_scheduled : nil
|
current_time = wizard.present? ? wizard.after_time_scheduled : nil
|
||||||
new_time = @params[:after_time_scheduled]
|
new_time = @data[:after_time_scheduled]
|
||||||
|
|
||||||
begin
|
begin
|
||||||
active_time = Time.parse(new_time.present? ? new_time : current_time).utc
|
active_time = Time.parse(new_time.present? ? new_time : current_time).utc
|
||||||
|
@ -115,7 +75,7 @@ class CustomWizard::Validator
|
||||||
end
|
end
|
||||||
|
|
||||||
if invalid_time || active_time.blank? || active_time < Time.now.utc
|
if invalid_time || active_time.blank? || active_time < Time.now.utc
|
||||||
@error = { type: 'after_time' }
|
errors.add :validation, I18n.t("wizard.validation.after_time")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -24,23 +24,26 @@ class CustomWizard::Wizard
|
||||||
:needs_categories,
|
:needs_categories,
|
||||||
:needs_groups,
|
:needs_groups,
|
||||||
:steps,
|
:steps,
|
||||||
|
:step_ids,
|
||||||
:actions,
|
:actions,
|
||||||
:user
|
:user,
|
||||||
|
:first_step
|
||||||
|
|
||||||
def initialize(attrs = {}, user=nil)
|
def initialize(attrs = {}, user=nil)
|
||||||
@user = user
|
@user = user
|
||||||
|
attrs = attrs.with_indifferent_access
|
||||||
|
|
||||||
@id = attrs['id']
|
@id = attrs['id']
|
||||||
@name = attrs['name']
|
@name = attrs['name']
|
||||||
@background = attrs['background']
|
@background = attrs['background']
|
||||||
@save_submissions = attrs['save_submissions'] || false
|
@save_submissions = cast_bool(attrs['save_submissions'])
|
||||||
@multiple_submissions = attrs['multiple_submissions'] || false
|
@multiple_submissions = cast_bool(attrs['multiple_submissions'])
|
||||||
@prompt_completion = attrs['prompt_completion'] || false
|
@prompt_completion = cast_bool(attrs['prompt_completion'])
|
||||||
@restart_on_revisit = attrs['restart_on_revisit'] || false
|
@restart_on_revisit = cast_bool(attrs['restart_on_revisit'])
|
||||||
@after_signup = attrs['after_signup']
|
@after_signup = cast_bool(attrs['after_signup'])
|
||||||
@after_time = attrs['after_time']
|
@after_time = cast_bool(attrs['after_time'])
|
||||||
@after_time_scheduled = attrs['after_time_scheduled']
|
@after_time_scheduled = attrs['after_time_scheduled']
|
||||||
@required = attrs['required'] || false
|
@required = cast_bool(attrs['required'])
|
||||||
@permitted = attrs['permitted'] || nil
|
@permitted = attrs['permitted'] || nil
|
||||||
@needs_categories = false
|
@needs_categories = false
|
||||||
@needs_groups = false
|
@needs_groups = false
|
||||||
|
@ -53,8 +56,16 @@ class CustomWizard::Wizard
|
||||||
|
|
||||||
@first_step = nil
|
@first_step = nil
|
||||||
@steps = []
|
@steps = []
|
||||||
|
if attrs['steps'].present?
|
||||||
|
@step_ids = attrs['steps'].map { |s| s['id'] }
|
||||||
|
end
|
||||||
|
|
||||||
@actions = []
|
@actions = []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def cast_bool(val)
|
||||||
|
val.nil? ? false : ActiveRecord::Type::Boolean.new.cast(val)
|
||||||
|
end
|
||||||
|
|
||||||
def create_step(step_name)
|
def create_step(step_name)
|
||||||
::Wizard::Step.new(step_name)
|
::Wizard::Step.new(step_name)
|
||||||
|
@ -65,12 +76,10 @@ 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
|
||||||
# If it's the first step
|
|
||||||
if @steps.size == 1
|
|
||||||
@first_step = step
|
@first_step = step
|
||||||
step.index = 0
|
step.index = 0
|
||||||
elsif last_step.present?
|
elsif last_step.present?
|
||||||
|
@ -81,67 +90,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, inputs)
|
||||||
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, inputs)
|
||||||
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?
|
||||||
|
@ -171,6 +175,7 @@ class CustomWizard::Wizard
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_access?
|
def can_access?
|
||||||
|
return false unless user
|
||||||
return true if user.admin
|
return true if user.admin
|
||||||
return permitted? && (multiple_submissions || !completed?)
|
return permitted? && (multiple_submissions || !completed?)
|
||||||
end
|
end
|
||||||
|
@ -178,173 +183,89 @@ 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 current_submission
|
||||||
PluginStoreRow.where("
|
if submissions.present? && !submissions.last.key?("submitted_at")
|
||||||
plugin_name = 'custom_wizard' AND
|
submissions.last
|
||||||
(value::json ->> '#{filter}')::boolean IS TRUE
|
else
|
||||||
")
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_submissions(submissions)
|
||||||
|
PluginStore.set("#{id}_submissions", user.id, Array.wrap(submissions))
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.submissions(wizard_id, user)
|
||||||
|
new({ id: wizard_id }, user).submissions
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.set_submissions(wizard_id, user, submissions)
|
||||||
|
new({ id: wizard_id }, user).set_submissions(submissions)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.create(wizard_id, user = nil)
|
||||||
|
if template = CustomWizard::Template.find(wizard_id)
|
||||||
|
new(template.to_h, user)
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.list(user, template_opts: {})
|
||||||
|
return [] unless user
|
||||||
|
|
||||||
|
CustomWizard::Template.list(template_opts).reduce([]) do |result, template|
|
||||||
|
wizard = new(template, user)
|
||||||
|
result.push(wizard) if wizard.can_access?
|
||||||
|
result
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.after_signup(user)
|
def self.after_signup(user)
|
||||||
if (records = filter_records('after_signup')).any?
|
wizards = list(
|
||||||
result = false
|
user,
|
||||||
|
template_opts: {
|
||||||
records
|
setting: 'after_signup',
|
||||||
.sort_by { |record| record.value['permitted'].present? ? 0 : 1 }
|
order: "(value::json ->> 'permitted') IS NOT NULL DESC"
|
||||||
.each do |record|
|
}
|
||||||
wizard = self.new(JSON.parse(record.value), user)
|
)
|
||||||
|
wizards.any? ? wizards.first : false
|
||||||
if wizard.permitted?
|
|
||||||
result = wizard
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
result
|
|
||||||
else
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.prompt_completion(user)
|
def self.prompt_completion(user)
|
||||||
if (records = filter_records('prompt_completion')).any?
|
wizards = list(
|
||||||
records.reduce([]) do |result, record|
|
user,
|
||||||
wizard = CustomWizard::Wizard.new(::JSON.parse(record.value), user)
|
template_opts: {
|
||||||
|
setting: 'prompt_completion',
|
||||||
if wizard.permitted? && !wizard.completed?
|
order: "(value::json ->> 'permitted') IS NOT NULL DESC"
|
||||||
result.push(id: wizard.id, name: wizard.name)
|
}
|
||||||
end
|
)
|
||||||
|
|
||||||
result
|
|
||||||
end
|
|
||||||
else
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.restart_on_revisit
|
|
||||||
if (records = filter_records('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 wizards.any?
|
||||||
if step[:raw_description]
|
wizards.map do |w|
|
||||||
step[:description] = PrettyText.cook(step[:raw_description])
|
{
|
||||||
|
id: w.id,
|
||||||
|
name: w.name
|
||||||
|
}
|
||||||
end
|
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
|
else
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
@ -364,12 +285,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
|
||||||
|
|
14
plugin.rb
14
plugin.rb
|
@ -42,10 +42,10 @@ after_initialize do
|
||||||
../controllers/custom_wizard/admin/submissions.rb
|
../controllers/custom_wizard/admin/submissions.rb
|
||||||
../controllers/custom_wizard/admin/api.rb
|
../controllers/custom_wizard/admin/api.rb
|
||||||
../controllers/custom_wizard/admin/logs.rb
|
../controllers/custom_wizard/admin/logs.rb
|
||||||
|
../controllers/custom_wizard/admin/transfer.rb
|
||||||
../controllers/custom_wizard/admin/custom_fields.rb
|
../controllers/custom_wizard/admin/custom_fields.rb
|
||||||
../controllers/custom_wizard/wizard.rb
|
../controllers/custom_wizard/wizard.rb
|
||||||
../controllers/custom_wizard/steps.rb
|
../controllers/custom_wizard/steps.rb
|
||||||
../controllers/custom_wizard/transfer.rb
|
|
||||||
../jobs/clear_after_time_wizard.rb
|
../jobs/clear_after_time_wizard.rb
|
||||||
../jobs/refresh_api_access_token.rb
|
../jobs/refresh_api_access_token.rb
|
||||||
../jobs/set_after_time_wizard.rb
|
../jobs/set_after_time_wizard.rb
|
||||||
|
@ -57,6 +57,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
|
||||||
|
@ -130,8 +131,7 @@ after_initialize do
|
||||||
if request.referer !~ /\/w\// && request.referer !~ /\/invites\//
|
if request.referer !~ /\/w\// && request.referer !~ /\/invites\//
|
||||||
CustomWizard::Wizard.set_submission_redirect(current_user, wizard_id, request.referer)
|
CustomWizard::Wizard.set_submission_redirect(current_user, wizard_id, request.referer)
|
||||||
end
|
end
|
||||||
|
if CustomWizard::Template.exists?(wizard_id)
|
||||||
if CustomWizard::Wizard.exists?(wizard_id)
|
|
||||||
redirect_to "/w/#{wizard_id.dasherize}"
|
redirect_to "/w/#{wizard_id.dasherize}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -161,8 +161,12 @@ 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
|
||||||
|
|
||||||
CustomWizard::CustomField::CLASSES.each do |klass|
|
CustomWizard::CustomField::CLASSES.each do |klass|
|
||||||
add_model_callback(klass.to_sym, :after_initialize) do
|
add_model_callback(klass.to_sym, :after_initialize) do
|
||||||
CustomWizard::CustomField.list_by('klass', klass).each do |field|
|
CustomWizard::CustomField.list_by('klass', klass).each do |field|
|
||||||
|
|
|
@ -1,92 +1,162 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
describe CustomWizard::Action do
|
describe CustomWizard::Action do
|
||||||
let(:create_topic_action) {{"id":"create_topic","type":"create_topic","title":"text","post":"textarea"}}
|
fab!(:user) { Fabricate(:user, name: "Angus", username: 'angus', email: "angus@email.com", trust_level: TrustLevel[2]) }
|
||||||
let(:send_message_action) {{"id":"send_message","type":"send_message","title":"text","post":"textarea","username":"angus"}}
|
fab!(:category) { Fabricate(:category, name: 'cat1', slug: 'cat-slug') }
|
||||||
let(:route_to_action) {{"id":"route_to","type":"route_to","url":"https://google.com"}}
|
fab!(:group) { Fabricate(:group) }
|
||||||
let(:open_composer_action) {{"id":"open_composer","type":"open_composer","title":"text","post":"textarea"}}
|
|
||||||
let(:add_to_group_action) {{"id":"add_to_group","type":"add_to_group","group_id":"dropdown_groups"}}
|
|
||||||
|
|
||||||
it 'creates a topic' do
|
before do
|
||||||
template['steps'][0]['fields'] = [text_field, textarea_field]
|
Group.refresh_automatic_group!(:trust_level_2)
|
||||||
template['steps'][0]["actions"] = [create_topic_action]
|
CustomWizard::Template.save(
|
||||||
updater = run_update(template, nil,
|
JSON.parse(File.open(
|
||||||
text: "Topic Title",
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
textarea: "topic body"
|
).read),
|
||||||
)
|
skip_jobs: true)
|
||||||
topic = Topic.where(title: "Topic Title")
|
@template = CustomWizard::Template.find('super_mega_fun_wizard')
|
||||||
|
end
|
||||||
|
|
||||||
|
context "creating a topic" do
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'creating a topic' do
|
||||||
|
it "works" do
|
||||||
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
wizard.create_updater(
|
||||||
|
wizard.steps.first.id,
|
||||||
|
step_1_field_1: "Topic Title",
|
||||||
|
step_1_field_2: "topic body"
|
||||||
|
).update
|
||||||
|
wizard.create_updater(wizard.steps.second.id, {}).update
|
||||||
|
wizard.create_updater(wizard.steps.last.id,
|
||||||
|
step_3_field_3: category.id
|
||||||
|
).update
|
||||||
|
|
||||||
|
topic = Topic.where(
|
||||||
|
title: "Topic Title",
|
||||||
|
category_id: category.id
|
||||||
|
)
|
||||||
|
expect(topic.exists?).to eq(true)
|
||||||
|
expect(Post.where(
|
||||||
|
topic_id: topic.pluck(:id),
|
||||||
|
raw: "topic body"
|
||||||
|
).exists?).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
expect(topic.exists?).to eq(true)
|
it "fails silently without basic topic inputs" do
|
||||||
expect(Post.where(
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
topic_id: topic.pluck(:id),
|
wizard.create_updater(
|
||||||
raw: "topic body"
|
wizard.steps.first.id,
|
||||||
).exists?).to eq(true)
|
step_1_field_2: "topic body"
|
||||||
|
).update
|
||||||
|
wizard.create_updater(wizard.steps.second.id, {}).update
|
||||||
|
updater = wizard.create_updater(wizard.steps.last.id, {})
|
||||||
|
updater.update
|
||||||
|
|
||||||
|
expect(updater.success?).to eq(true)
|
||||||
|
expect(UserHistory.where(
|
||||||
|
acting_user_id: user.id,
|
||||||
|
context: "super_mega_fun_wizard",
|
||||||
|
subject: "step_3"
|
||||||
|
).exists?).to eq(true)
|
||||||
|
expect(Post.where(
|
||||||
|
raw: "topic body"
|
||||||
|
).exists?).to eq(false)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'sends a message' do
|
it 'sends a message' do
|
||||||
fields = [text_field, textarea_field]
|
User.create(username: 'angus1', email: "angus1@email.com")
|
||||||
|
|
||||||
if extra_field
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
fields.push(extra_field)
|
wizard.create_updater(wizard.steps[0].id, {}).update
|
||||||
end
|
wizard.create_updater(wizard.steps[1].id, {}).update
|
||||||
|
|
||||||
template['steps'][0]['fields'] = fields
|
|
||||||
template['steps'][0]["actions"] = [send_message_action.merge(extra_action_opts)]
|
|
||||||
|
|
||||||
run_update(template, nil,
|
|
||||||
text: "Message Title",
|
|
||||||
textarea: "message body"
|
|
||||||
)
|
|
||||||
|
|
||||||
topic = Topic.where(
|
topic = Topic.where(
|
||||||
archetype: Archetype.private_message,
|
archetype: Archetype.private_message,
|
||||||
title: "Message Title"
|
title: "Message title"
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(topic.exists?).to eq(true)
|
post = Post.where(
|
||||||
expect(
|
|
||||||
topic.first.topic_allowed_users.first.user.username
|
|
||||||
).to eq('angus')
|
|
||||||
expect(Post.where(
|
|
||||||
topic_id: topic.pluck(:id),
|
topic_id: topic.pluck(:id),
|
||||||
raw: "message body"
|
raw: "I will interpolate some wizard fields"
|
||||||
).exists?).to eq(true)
|
)
|
||||||
|
|
||||||
|
expect(topic.exists?).to eq(true)
|
||||||
|
expect(topic.first.topic_allowed_users.first.user.username).to eq('angus1')
|
||||||
|
expect(post.exists?).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'updates a profile' do
|
it 'updates a profile' do
|
||||||
run_update(template, template['steps'][1]['id'], name: "Sally")
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
expect(user.name).to eq('Sally')
|
upload = Upload.create!(
|
||||||
|
url: '/images/image.png',
|
||||||
|
original_filename: 'image.png',
|
||||||
|
filesize: 100,
|
||||||
|
user_id: -1,
|
||||||
|
)
|
||||||
|
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
|
end
|
||||||
|
|
||||||
it 'opens a composer' do
|
it 'opens a composer' do
|
||||||
template['steps'][0]['fields'] = [text_field, textarea_field]
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
template['steps'][0]["actions"] = [open_composer_action]
|
wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update
|
||||||
|
|
||||||
updater = run_update(template, nil,
|
updater = wizard.create_updater(wizard.steps[1].id, {})
|
||||||
text: "Topic Title",
|
updater.update
|
||||||
textarea: "topic body"
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(updater.result.blank?).to eq(true)
|
category = Category.find_by(id: wizard.current_submission['action_8'])
|
||||||
|
|
||||||
updater = run_update(template, template['steps'][1]['id'])
|
expect(updater.result[:redirect_on_next]).to eq(
|
||||||
|
"/new-topic?title=Title%20of%20the%20composer%20topic&body=I%20am%20interpolating%20some%20user%20fields%20Angus%20angus%20angus@email.com&category=#{category.slug}/#{category.id}&tags=tag1"
|
||||||
expect(updater.result[:redirect_on_complete]).to eq(
|
|
||||||
"/new-topic?title=Topic%20Title&body=topic%20body"
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'adds a user to a group' do
|
it 'creates a category' do
|
||||||
template['steps'][0]['fields'] = [dropdown_groups_field]
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
template['steps'][0]["actions"] = [add_to_group_action]
|
wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update
|
||||||
|
wizard.create_updater(wizard.steps[1].id, {}).update
|
||||||
updater = run_update(template, nil, dropdown_groups: group.id)
|
expect(Category.where(id: wizard.current_submission['action_8']).exists?).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates a group' do
|
||||||
|
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
|
||||||
|
expect(Group.where(name: wizard.current_submission['action_9']).exists?).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'adds a user to a group' do
|
||||||
|
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
|
||||||
|
group = Group.find_by(name: wizard.current_submission['action_9'])
|
||||||
expect(group.users.first.username).to eq('angus')
|
expect(group.users.first.username).to eq('angus')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'watches categories' do
|
||||||
|
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
|
||||||
|
expect(CategoryUser.where(
|
||||||
|
category_id: wizard.current_submission['action_8'],
|
||||||
|
user_id: user.id
|
||||||
|
).first.notification_level).to eq(2)
|
||||||
|
expect(CategoryUser.where(
|
||||||
|
category_id: category.id,
|
||||||
|
user_id: user.id
|
||||||
|
).first.notification_level).to eq(0)
|
||||||
|
end
|
||||||
|
|
||||||
it 're-routes a user' do
|
it 're-routes a user' do
|
||||||
template['steps'][0]["actions"] = [route_to_action]
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
updater = run_update(template, nil, {})
|
updater = wizard.create_updater(wizard.steps.last.id, {})
|
||||||
expect(updater.result[:redirect_on_next]).to eq(
|
updater.update
|
||||||
"https://google.com"
|
expect(updater.result[:redirect_on_complete]).to eq("https://google.com")
|
||||||
)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'rails_helper'
|
|
||||||
|
|
||||||
describe CustomWizard::Api do
|
|
||||||
context 'authorization' do
|
|
||||||
it 'authorizes with an oauth2 api' do
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'refreshes the api access token' do
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'endpoint' do
|
|
||||||
it 'requests an api endpoint' do
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -3,39 +3,45 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
describe CustomWizard::Builder do
|
describe CustomWizard::Builder do
|
||||||
fab!(:user) { Fabricate(:user, username: 'angus') }
|
fab!(:trusted_user) {
|
||||||
fab!(:trusted_user) { Fabricate(:user, trust_level: 3) }
|
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) }
|
||||||
|
|
||||||
let!(:template) do
|
let(:required_data_json) {
|
||||||
JSON.parse(File.open(
|
JSON.parse(File.open(
|
||||||
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/step/required_data.json"
|
||||||
).read)
|
).read)
|
||||||
end
|
}
|
||||||
|
|
||||||
def build_wizard(t = template, u = user, build_opts = {}, params = {})
|
let(:permitted_json) {
|
||||||
CustomWizard::Wizard.add_wizard(t)
|
JSON.parse(File.open(
|
||||||
CustomWizard::Builder.new('welcome', u).build(build_opts, params)
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/permitted.json"
|
||||||
end
|
).read)
|
||||||
|
}
|
||||||
|
|
||||||
def add_submission_data(data = {})
|
let(:permitted_param_json) {
|
||||||
PluginStore.set("welcome_submissions", user.id, {
|
JSON.parse(File.open(
|
||||||
name: 'Angus',
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/step/permitted_params.json"
|
||||||
website: 'https://thepavilion.io'
|
).read)
|
||||||
}.merge(data))
|
}
|
||||||
end
|
|
||||||
|
|
||||||
def get_submission_data
|
before do
|
||||||
PluginStore.get("welcome_submissions", user.id)
|
Group.refresh_automatic_group!(:trust_level_3)
|
||||||
end
|
CustomWizard::Template.save(
|
||||||
|
JSON.parse(File.open(
|
||||||
def run_update(t = template, step_id = nil, data = {})
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
wizard = build_wizard(t)
|
).read),
|
||||||
updater = wizard.create_updater(step_id || t['steps'][0]['id'], data)
|
skip_jobs: true)
|
||||||
updater.update
|
@template = CustomWizard::Template.find('super_mega_fun_wizard')
|
||||||
updater
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'disabled' do
|
context 'disabled' do
|
||||||
|
@ -43,15 +49,10 @@ describe CustomWizard::Builder do
|
||||||
SiteSetting.custom_wizard_enabled = false
|
SiteSetting.custom_wizard_enabled = false
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns no steps" do
|
it "returns nil" do
|
||||||
wizard = build_wizard
|
expect(
|
||||||
expect(wizard.steps.length).to eq(0)
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
expect(wizard.name).to eq('Welcome')
|
).to eq(nil)
|
||||||
end
|
|
||||||
|
|
||||||
it "doesn't save submissions" do
|
|
||||||
run_update(template, nil, name: 'Angus')
|
|
||||||
expect(get_submission_data.blank?).to eq(true)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -60,124 +61,288 @@ 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(build_wizard.steps.length).to eq(2)
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.steps.length
|
||||||
|
).to eq(3)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns no steps if multiple submissions are disabled and user has completed' do
|
context "with multiple submissions disabled" do
|
||||||
history_params = {
|
before do
|
||||||
action: UserHistory.actions[:custom_wizard_step],
|
@template[:multiple_submissions] = false
|
||||||
acting_user_id: user.id,
|
CustomWizard::Template.save(@template.as_json)
|
||||||
context: template['id']
|
end
|
||||||
}
|
|
||||||
UserHistory.create!(history_params.merge(subject: template['steps'][0]['id']))
|
|
||||||
UserHistory.create!(history_params.merge(subject: template['steps'][1]['id']))
|
|
||||||
|
|
||||||
template["multiple_submissions"] = false
|
it 'returns steps if user has not completed it' do
|
||||||
expect(build_wizard(template).steps.length).to eq(0)
|
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: @template[:id]
|
||||||
|
}.merge(
|
||||||
|
subject: step[:id]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.steps.length
|
||||||
|
).to eq(0)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns no steps if user is not permitted' do
|
context "with restricted permissions" do
|
||||||
template["min_trust"] = 3
|
before do
|
||||||
expect(build_wizard(template).steps.length).to eq(0)
|
@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(@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(@template[:id], trusted_user).build
|
||||||
|
.steps.length
|
||||||
|
).to eq(3)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns steps if user is permitted' do
|
it 'returns prefilled data' do
|
||||||
template["min_trust"] = 3
|
expect(
|
||||||
expect(build_wizard(template, trusted_user).steps.length).to eq(2)
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.steps.first
|
||||||
|
.fields.first
|
||||||
|
.value
|
||||||
|
).to eq('I am prefilled')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns a wizard with prefilled data if user has partially completed it' do
|
context "user has partially completed" do
|
||||||
add_submission_data
|
before do
|
||||||
wizard = build_wizard
|
wizard = CustomWizard::Wizard.new(@template, user)
|
||||||
expect(wizard.steps[0].fields.first.value).to eq('Angus')
|
wizard.set_submissions(step_1_field_1: 'I am a user submission')
|
||||||
expect(wizard.steps[1].fields.first.value).to eq('https://thepavilion.io')
|
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
|
end
|
||||||
|
|
||||||
it 'returns a wizard with no prefilled data if options include reset' do
|
context 'building step' do
|
||||||
add_submission_data
|
|
||||||
wizard = build_wizard(template, user, reset: true)
|
|
||||||
expect(wizard.steps[0].fields.first.value).to eq(nil)
|
|
||||||
expect(wizard.steps[1].fields.first.value).to eq(nil)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'building steps' do
|
|
||||||
it 'returns step metadata' do
|
it 'returns step metadata' do
|
||||||
expect(build_wizard.steps[0].title).to eq('Welcome to Pavilion')
|
first_step = CustomWizard::Builder.new(@template[:id], user)
|
||||||
expect(build_wizard.steps[1].title).to eq('Tell us about you')
|
.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
|
end
|
||||||
|
|
||||||
it 'saves permitted params' do
|
context 'with required data' do
|
||||||
template['steps'][0]['permitted_params'] = permitted_params
|
before do
|
||||||
wizard = build_wizard(template, user, {}, param_key: 'param_value')
|
@template[:steps][0][:required_data] = required_data_json['required_data']
|
||||||
submissions = get_submission_data
|
@template[:steps][0][:required_data_message] = required_data_json['required_data_message']
|
||||||
expect(submissions.first['submission_param_key']).to eq('param_value')
|
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
|
||||||
|
CustomWizard::Wizard.set_submissions('super_mega_fun_wizard', user,
|
||||||
|
required_data: "required_value"
|
||||||
|
)
|
||||||
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.steps.first
|
||||||
|
.permitted
|
||||||
|
).to eq(true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'is not permitted if required data is not present' do
|
context "with permitted params" do
|
||||||
template['steps'][0]['required_data'] = required_data
|
before do
|
||||||
expect(build_wizard(template, user).steps[0].permitted).to eq(false)
|
@template[:steps][0][:permitted_params] = permitted_param_json['permitted_params']
|
||||||
|
CustomWizard::Template.save(@template.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'saves permitted params' do
|
||||||
|
wizard = CustomWizard::Builder.new(@template[:id], user).build({},
|
||||||
|
param: 'param_value'
|
||||||
|
)
|
||||||
|
expect(wizard.current_submission['saved_param']).to eq('param_value')
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
it 'it shows required data message if required data has message' do
|
|
||||||
template['steps'][0]['required_data'] = required_data
|
context 'building field' do
|
||||||
template['steps'][0]['required_data_message'] = required_data_message
|
|
||||||
add_submission_data(nickname: "John")
|
|
||||||
wizard = build_wizard(template, user)
|
|
||||||
expect(wizard.steps[0].permitted).to eq(false)
|
|
||||||
expect(wizard.steps[0].permitted_message).to eq(required_data_message)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'is permitted if required data is present' do
|
|
||||||
template['steps'][0]['required_data'] = required_data
|
|
||||||
PluginStore.set('welcome_submissions', user.id, nickname: "Angus", name: "Angus")
|
|
||||||
expect(build_wizard(template, user).steps[0].permitted).to eq(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns field metadata' do
|
it 'returns field metadata' do
|
||||||
expect(build_wizard(template, user).steps[0].fields[0].label).to eq("<p>Name</p>")
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
expect(build_wizard(template, user).steps[0].fields[0].type).to eq("text")
|
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
|
end
|
||||||
|
|
||||||
it 'returns fields' do
|
it 'returns all step fields' do
|
||||||
template['steps'][0]['fields'][1] = checkbox_field
|
expect(
|
||||||
expect(build_wizard(template, user).steps[0].fields.length).to eq(2)
|
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
|
||||||
run_update(template, nil, name: 'Angus')
|
perform_update('step_1', step_1_field_1: 'Text input')
|
||||||
expect(get_submission_data.first['name']).to eq('Angus')
|
expect(
|
||||||
|
CustomWizard::Wizard.submissions(@template[:id], user)
|
||||||
|
.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(
|
||||||
|
CustomWizard::Wizard.submissions(@template[:id], user).first
|
||||||
|
).to eq(nil)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'validation' do
|
context 'validation' do
|
||||||
it 'applies min length' do
|
it 'applies min length' do
|
||||||
template['steps'][0]['fields'][0]['min_length'] = 10
|
expect(
|
||||||
updater = run_update(template, nil, name: 'short')
|
perform_update('step_1', step_1_field_1: 'Te')
|
||||||
expect(updater.errors.messages[:name].first).to eq(
|
.errors.messages[:step_1_field_1].first
|
||||||
I18n.t('wizard.field.too_short', label: 'Name', min: 10)
|
).to eq(I18n.t('wizard.field.too_short', label: 'Text', min: 3))
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'standardises boolean entries' do
|
it 'standardises boolean entries' do
|
||||||
template['steps'][0]['fields'][0] = checkbox_field
|
perform_update('step_2', step_2_field_5: 'false')
|
||||||
run_update(template, nil, checkbox: 'false')
|
expect(
|
||||||
expect(get_submission_data.first['checkbox']).to eq(false)
|
CustomWizard::Wizard.submissions(@template[:id], user)
|
||||||
|
.first['step_2_field_5']
|
||||||
|
).to eq(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'requires required fields' do
|
it 'requires required fields' do
|
||||||
template['steps'][0]['fields'][0]['required'] = true
|
@template[:steps][0][:fields][1][:required] = true
|
||||||
expect(run_update(template).errors.messages[:name].first).to eq(
|
CustomWizard::Template.save(@template.as_json)
|
||||||
I18n.t('wizard.field.required', label: 'Name')
|
|
||||||
)
|
expect(
|
||||||
|
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
|
end
|
||||||
|
|
||||||
it 'runs actions attached to a step' do
|
|
||||||
run_update(template, template['steps'][1]['id'], name: "Gus")
|
|
||||||
expect(user.name).to eq('Gus')
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
30
spec/components/custom_wizard/field_spec.rb
Normale Datei
30
spec/components/custom_wizard/field_spec.rb
Normale Datei
|
@ -0,0 +1,30 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe CustomWizard::Field do
|
||||||
|
before do
|
||||||
|
CustomWizard::Field.register(
|
||||||
|
'location',
|
||||||
|
'discourse-locations',
|
||||||
|
['components', 'helpers', 'lib', 'stylesheets', 'templates'],
|
||||||
|
type_opts: {
|
||||||
|
prefill: { "coordinates": [35.3082, 149.1244] }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "registers custom field types" do
|
||||||
|
expect(CustomWizard::Field.types[:location].present?).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "allows custom field types to set default attributes" do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Field.types[:location][:prefill]
|
||||||
|
).to eq({ "coordinates": [35.3082, 149.1244] })
|
||||||
|
end
|
||||||
|
|
||||||
|
it "registers custom field assets" do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Field.require_assets['discourse-locations']
|
||||||
|
).to eq(['components', 'helpers', 'lib', 'stylesheets', 'templates'])
|
||||||
|
end
|
||||||
|
end
|
27
spec/components/custom_wizard/log_spec.rb
Normale Datei
27
spec/components/custom_wizard/log_spec.rb
Normale Datei
|
@ -0,0 +1,27 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe CustomWizard::Log do
|
||||||
|
before do
|
||||||
|
CustomWizard::Log.create("First log message")
|
||||||
|
CustomWizard::Log.create("Second log message")
|
||||||
|
CustomWizard::Log.create("Third log message")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "creates logs" do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Log.list.length
|
||||||
|
).to eq(3)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "lists logs by time created" do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Log.list.first.message
|
||||||
|
).to eq("Third log message")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "paginates logs" do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Log.list(0, 2).length
|
||||||
|
).to eq(2)
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,14 +1,250 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
describe CustomWizard::Mapper do
|
describe CustomWizard::Mapper do
|
||||||
|
fab!(:user1) {
|
||||||
it 'interpolates user data' do
|
Fabricate(:user,
|
||||||
user.name = "Angus"
|
name: "Angus",
|
||||||
user.save!
|
username: "angus",
|
||||||
|
email: "angus@email.com",
|
||||||
expect(
|
trust_level: TrustLevel[3]
|
||||||
CustomWizard::Builder.fill_placeholders(
|
|
||||||
"My name is u{name}",
|
|
||||||
user,
|
|
||||||
{}
|
|
||||||
)
|
)
|
||||||
).to eq('My name is Angus')
|
}
|
||||||
|
fab!(:user2) {
|
||||||
|
Fabricate(:user,
|
||||||
|
name: "Patrick",
|
||||||
|
username: "patrick",
|
||||||
|
email: "patrick@email2.com",
|
||||||
|
trust_level: TrustLevel[1]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
fab!(:user_field) {
|
||||||
|
field = Fabricate(:user_field,
|
||||||
|
id: 3,
|
||||||
|
name: 'dropdown_field',
|
||||||
|
description: 'field desc',
|
||||||
|
field_type: 'dropdown',
|
||||||
|
user_field_options_attributes: [
|
||||||
|
{ value: "a" },
|
||||||
|
{ value: "b" },
|
||||||
|
{ value: "c" }
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
let(:inputs) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/mapper/inputs.json"
|
||||||
|
).read)
|
||||||
|
}
|
||||||
|
let(:data) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/mapper/data.json"
|
||||||
|
).read)
|
||||||
|
}
|
||||||
|
|
||||||
|
it "maps values" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['assignment'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq([13])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "maps associations" do
|
||||||
|
association = CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['association'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform
|
||||||
|
expect(association.length).to eq(3)
|
||||||
|
expect(association.first[:value]).to eq("Choice 1")
|
||||||
|
end
|
||||||
|
|
||||||
|
context "conditional mapping" do
|
||||||
|
it "maps when the condition is met" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['conditional'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq("true")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not map when the condition is not met" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['conditional'],
|
||||||
|
data: data,
|
||||||
|
user: user2
|
||||||
|
).perform).to eq(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "maps when multiple conditions are met" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['conditional_multiple_pairs'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq("true")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not map when one of multiple conditions are not met" do
|
||||||
|
user1.email = "angus@other-email.com"
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['conditional_multiple_pairs'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "validates valid data" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['validation'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not validate invalid data" do
|
||||||
|
data["input_2"] = "value 3"
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['validation'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "maps text fields" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['assignment_text'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq("Value")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "maps user fields" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['assignment_user_field'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq("Angus")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "maps user field options" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['assignment_user_field_options'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq(["a", "b", "c"])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "maps wizard fields" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['assignment_wizard_field'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq("value 1")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "maps wizard actions" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['assignment_wizard_action'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq("value 2")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "interpolates user fields" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['interpolate_user_field'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq("Name: Angus")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "interpolates wizard fields" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['interpolate_wizard_field'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq("Input 1: value 1")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "interpolates date" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['interpolate_timestamp'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq("Time: #{Time.now.strftime("%B %-d, %Y")}")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "handles greater than pairs" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['greater_than_pair'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq(true)
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['greater_than_pair'],
|
||||||
|
data: data,
|
||||||
|
user: user2
|
||||||
|
).perform).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "handles less than pairs" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['less_than_pair'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq(false)
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['less_than_pair'],
|
||||||
|
data: data,
|
||||||
|
user: user2
|
||||||
|
).perform).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "handles greater than or equal pairs" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['greater_than_or_equal_pair'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq(true)
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['greater_than_or_equal_pair'],
|
||||||
|
data: data,
|
||||||
|
user: user2
|
||||||
|
).perform).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "handles less than or equal pairs" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['less_than_or_equal_pair'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq(true)
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['less_than_or_equal_pair'],
|
||||||
|
data: data,
|
||||||
|
user: user2
|
||||||
|
).perform).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "handles regex pairs" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['regex_pair'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq(true)
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['regex_pair'],
|
||||||
|
data: data,
|
||||||
|
user: user2
|
||||||
|
).perform).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "handles shorthand pairs" do
|
||||||
|
expect(CustomWizard::Mapper.new(
|
||||||
|
inputs: inputs['shorthand_pair'],
|
||||||
|
data: data,
|
||||||
|
user: user1
|
||||||
|
).perform).to eq(false)
|
||||||
|
end
|
||||||
end
|
end
|
111
spec/components/custom_wizard/template_spec.rb
Normale Datei
111
spec/components/custom_wizard/template_spec.rb
Normale Datei
|
@ -0,0 +1,111 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe CustomWizard::Template do
|
||||||
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
|
let(:template_json) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
|
).read)
|
||||||
|
}
|
||||||
|
let(:permitted_json) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/permitted.json"
|
||||||
|
).read)
|
||||||
|
}
|
||||||
|
let(:after_time) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/after_time.json"
|
||||||
|
).read).with_indifferent_access
|
||||||
|
}
|
||||||
|
|
||||||
|
before do
|
||||||
|
CustomWizard::Template.save(template_json, skip_jobs: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "saves wizard templates" do
|
||||||
|
expect(
|
||||||
|
PluginStoreRow.exists?(
|
||||||
|
plugin_name: 'custom_wizard',
|
||||||
|
key: 'super_mega_fun_wizard'
|
||||||
|
)
|
||||||
|
).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "finds wizard templates" do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Template.find('super_mega_fun_wizard')['id']
|
||||||
|
).to eq('super_mega_fun_wizard')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "removes wizard templates" do
|
||||||
|
CustomWizard::Template.remove('super_mega_fun_wizard')
|
||||||
|
expect(
|
||||||
|
CustomWizard::Template.find('super_mega_fun_wizard')
|
||||||
|
).to eq(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "checks for wizard template existence" do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Template.exists?('super_mega_fun_wizard')
|
||||||
|
).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "wizard template list" do
|
||||||
|
before do
|
||||||
|
template_json_2 = template_json.dup
|
||||||
|
template_json_2["id"] = 'super_mega_fun_wizard_2'
|
||||||
|
template_json_2["permitted"] = permitted_json['permitted']
|
||||||
|
CustomWizard::Template.save(template_json_2, skip_jobs: true)
|
||||||
|
|
||||||
|
template_json_3 = template_json.dup
|
||||||
|
template_json_3["id"] = 'super_mega_fun_wizard_3'
|
||||||
|
template_json_3["after_signup"] = true
|
||||||
|
CustomWizard::Template.save(template_json_3, skip_jobs: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "works" do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Template.list.length
|
||||||
|
).to eq(3)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can be filtered by wizard settings" do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Template.list(setting: "after_signup").length
|
||||||
|
).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can be ordered" do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Template.list(
|
||||||
|
order: "(value::json ->> 'permitted') IS NOT NULL DESC"
|
||||||
|
).first['id']
|
||||||
|
).to eq('super_mega_fun_wizard_2')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "after time setting" do
|
||||||
|
before do
|
||||||
|
freeze_time Time.now
|
||||||
|
@after_time_template = template_json.dup
|
||||||
|
@after_time_template["after_time"] = after_time['after_time']
|
||||||
|
@after_time_template["after_time_scheduled"] = after_time['after_time_scheduled']
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'if enabled queues jobs after wizard is saved' do
|
||||||
|
expect_enqueued_with(job: :set_after_time_wizard, at: Time.parse(after_time['after_time_scheduled']).utc) do
|
||||||
|
CustomWizard::Template.save(@after_time_template)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'if disabled clears jobs after wizard is saved' do
|
||||||
|
CustomWizard::Template.save(@after_time_template)
|
||||||
|
@after_time_template['after_time'] = false
|
||||||
|
|
||||||
|
expect_not_enqueued_with(job: :set_after_time_wizard) do
|
||||||
|
CustomWizard::Template.save(@after_time_template)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
53
spec/components/custom_wizard/validator_spec.rb
Normale Datei
53
spec/components/custom_wizard/validator_spec.rb
Normale Datei
|
@ -0,0 +1,53 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe CustomWizard::Validator do
|
||||||
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
|
let(:template) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
|
).read).with_indifferent_access
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:after_time) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/after_time.json"
|
||||||
|
).read).with_indifferent_access
|
||||||
|
}
|
||||||
|
|
||||||
|
it "validates valid templates" do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Validator.new(template).perform
|
||||||
|
).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "invalidates templates without required attributes" do
|
||||||
|
template.delete(:id)
|
||||||
|
expect(
|
||||||
|
CustomWizard::Validator.new(template).perform
|
||||||
|
).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "invalidates templates with duplicate ids if creating a new template" do
|
||||||
|
CustomWizard::Template.save(template)
|
||||||
|
expect(
|
||||||
|
CustomWizard::Validator.new(template, create: true).perform
|
||||||
|
).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "validates after time settings" do
|
||||||
|
template[:after_time] = after_time[:after_time]
|
||||||
|
template[:after_time_scheduled] = after_time[:after_time_scheduled]
|
||||||
|
expect(
|
||||||
|
CustomWizard::Validator.new(template).perform
|
||||||
|
).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "invalidates invalid after time settings" do
|
||||||
|
template[:after_time] = after_time[:after_time]
|
||||||
|
template[:after_time_scheduled] = "not a time"
|
||||||
|
expect(
|
||||||
|
CustomWizard::Validator.new(template).perform
|
||||||
|
).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
230
spec/components/custom_wizard/wizard_spec.rb
Normale Datei
230
spec/components/custom_wizard/wizard_spec.rb
Normale Datei
|
@ -0,0 +1,230 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe CustomWizard::Wizard do
|
||||||
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
fab!(:trusted_user) { Fabricate(:user, trust_level: TrustLevel[3])}
|
||||||
|
fab!(:admin_user) { Fabricate(:user, admin: true)}
|
||||||
|
|
||||||
|
let(:template_json) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
|
).read)
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:after_time) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/after_time.json"
|
||||||
|
).read)
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:permitted_json) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/permitted.json"
|
||||||
|
).read)
|
||||||
|
}
|
||||||
|
|
||||||
|
before do
|
||||||
|
Group.refresh_automatic_group!(:trust_level_3)
|
||||||
|
|
||||||
|
@permitted_template = template_json.dup
|
||||||
|
@permitted_template["permitted"] = permitted_json["permitted"]
|
||||||
|
|
||||||
|
@wizard = CustomWizard::Wizard.new(template_json, user)
|
||||||
|
template_json['steps'].each do |step_template|
|
||||||
|
@wizard.append_step(step_template['id'])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def progress_step(step_id, acting_user = user)
|
||||||
|
UserHistory.create(
|
||||||
|
action: UserHistory.actions[:custom_wizard_step],
|
||||||
|
acting_user_id: acting_user.id,
|
||||||
|
context: @wizard.id,
|
||||||
|
subject: step_id
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "appends steps from a template" do
|
||||||
|
expect(@wizard.steps.length).to eq(3)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "determines the user's current step" do
|
||||||
|
expect(@wizard.start.id).to eq('step_1')
|
||||||
|
progress_step('step_1')
|
||||||
|
expect(@wizard.start.id).to eq('step_2')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "creates a step updater" do
|
||||||
|
expect(
|
||||||
|
@wizard.create_updater('step_1', step_1_field_1: "Text input")
|
||||||
|
.class
|
||||||
|
).to eq(CustomWizard::StepUpdater)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "determines whether a wizard is unfinished" do
|
||||||
|
expect(@wizard.unfinished?).to eq(true)
|
||||||
|
progress_step("step_1")
|
||||||
|
expect(@wizard.unfinished?).to eq(true)
|
||||||
|
progress_step("step_2")
|
||||||
|
expect(@wizard.unfinished?).to eq(true)
|
||||||
|
progress_step("step_3")
|
||||||
|
expect(@wizard.unfinished?).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "determines whether a wizard has been completed by a user" do
|
||||||
|
expect(@wizard.completed?).to eq(false)
|
||||||
|
progress_step("step_1")
|
||||||
|
progress_step("step_2")
|
||||||
|
progress_step("step_3")
|
||||||
|
expect(@wizard.completed?).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is not completed if steps submitted before after time" do
|
||||||
|
progress_step("step_1")
|
||||||
|
progress_step("step_2")
|
||||||
|
progress_step("step_3")
|
||||||
|
|
||||||
|
template_json['after_time'] = after_time['after_time']
|
||||||
|
template_json['after_time_scheduled'] = after_time['after_time_scheduled']
|
||||||
|
|
||||||
|
wizard = CustomWizard::Wizard.new(template_json, user)
|
||||||
|
|
||||||
|
expect(wizard.completed?).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "permits admins" do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Wizard.new(@permitted_template, admin_user).permitted?
|
||||||
|
).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "permits permitted users" do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Wizard.new(@permitted_template, trusted_user).permitted?
|
||||||
|
).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not permit unpermitted users" do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Wizard.new(@permitted_template, user).permitted?
|
||||||
|
).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not let an unpermitted user access a wizard" do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Wizard.new(@permitted_template, user).can_access?
|
||||||
|
).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "lets a permitted user access an incomplete wizard" do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Wizard.new(@permitted_template, trusted_user).can_access?
|
||||||
|
).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "lets a permitted user access a complete wizard with multiple submissions" do
|
||||||
|
progress_step("step_1", trusted_user)
|
||||||
|
progress_step("step_2", trusted_user)
|
||||||
|
progress_step("step_3", trusted_user)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
CustomWizard::Wizard.new(@permitted_template, trusted_user).can_access?
|
||||||
|
).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not let an unpermitted user access a complete wizard without multiple submissions" do
|
||||||
|
progress_step("step_1", trusted_user)
|
||||||
|
progress_step("step_2", trusted_user)
|
||||||
|
progress_step("step_3", trusted_user)
|
||||||
|
|
||||||
|
@permitted_template['multiple_submissions'] = false
|
||||||
|
|
||||||
|
expect(
|
||||||
|
CustomWizard::Wizard.new(@permitted_template, trusted_user).can_access?
|
||||||
|
).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "lists the site groups" do
|
||||||
|
expect(@wizard.groups.length).to eq(8)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "lists the site categories" do
|
||||||
|
expect(@wizard.categories.length).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "submissions" do
|
||||||
|
before do
|
||||||
|
@wizard.set_submissions(step_1_field_1: 'I am a user submission')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets the user's submission" do
|
||||||
|
expect(
|
||||||
|
PluginStore.get("#{template_json['id']}_submissions", user.id)
|
||||||
|
.first['step_1_field_1']
|
||||||
|
).to eq('I am a user submission')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "lists the user's submissions" do
|
||||||
|
expect(@wizard.submissions.length).to eq(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the user's current submission" do
|
||||||
|
expect(@wizard.current_submission['step_1_field_1']).to eq('I am a user submission')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "provides class methods to set and list submissions" do
|
||||||
|
CustomWizard::Wizard.set_submissions(template_json['id'], user,
|
||||||
|
step_1_field_1: 'I am a user submission'
|
||||||
|
)
|
||||||
|
expect(
|
||||||
|
CustomWizard::Wizard.submissions(template_json['id'], user)
|
||||||
|
.first['step_1_field_1']
|
||||||
|
).to eq('I am a user submission')
|
||||||
|
end
|
||||||
|
|
||||||
|
context do
|
||||||
|
before do
|
||||||
|
CustomWizard::Template.save(@permitted_template, skip_jobs: true)
|
||||||
|
|
||||||
|
template_json_2 = template_json.dup
|
||||||
|
template_json_2["id"] = 'super_mega_fun_wizard_2'
|
||||||
|
template_json_2["prompt_completion"] = true
|
||||||
|
CustomWizard::Template.save(template_json_2, skip_jobs: true)
|
||||||
|
|
||||||
|
template_json_3 = template_json.dup
|
||||||
|
template_json_3["id"] = 'super_mega_fun_wizard_3'
|
||||||
|
template_json_3["after_signup"] = true
|
||||||
|
CustomWizard::Template.save(template_json_3, skip_jobs: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "lists wizards the user can see" do
|
||||||
|
expect(CustomWizard::Wizard.list(user).length).to eq(2)
|
||||||
|
expect(CustomWizard::Wizard.list(trusted_user).length).to eq(3)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the first after signup wizard" do
|
||||||
|
expect(CustomWizard::Wizard.after_signup(user).id).to eq('super_mega_fun_wizard_3')
|
||||||
|
end
|
||||||
|
|
||||||
|
it "lists prompt completion wizards" do
|
||||||
|
expect(CustomWizard::Wizard.prompt_completion(user).length).to eq(2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "sets wizard redirects if user is permitted" do
|
||||||
|
CustomWizard::Template.save(@permitted_template, skip_jobs: true)
|
||||||
|
CustomWizard::Wizard.set_wizard_redirect('super_mega_fun_wizard', trusted_user)
|
||||||
|
expect(
|
||||||
|
trusted_user.custom_fields['redirect_to_wizard']
|
||||||
|
).to eq("super_mega_fun_wizard")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not set a wizard redirect if user is not permitted" do
|
||||||
|
CustomWizard::Template.save(@permitted_template, skip_jobs: true)
|
||||||
|
CustomWizard::Wizard.set_wizard_redirect('super_mega_fun_wizard', user)
|
||||||
|
expect(
|
||||||
|
trusted_user.custom_fields['redirect_to_wizard']
|
||||||
|
).to eq(nil)
|
||||||
|
end
|
||||||
|
end
|
23
spec/extensions/extra_locales_controller_spec.rb
Normale Datei
23
spec/extensions/extra_locales_controller_spec.rb
Normale Datei
|
@ -0,0 +1,23 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe ExtraLocalesControllerCustomWizard, type: :request do
|
||||||
|
before do
|
||||||
|
CustomWizard::Template.save(
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
|
).read),
|
||||||
|
skip_jobs: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
@controller = ExtraLocalesController.new
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns locales when requested by wizard" do
|
||||||
|
expect(
|
||||||
|
ExtraLocalesController.url("wizard")
|
||||||
|
).to eq(
|
||||||
|
"#{Discourse.base_path}/extra-locales/wizard?v=#{ExtraLocalesController.bundle_js_hash("wizard")}"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
24
spec/extensions/invites_controller_spec.rb
Normale Datei
24
spec/extensions/invites_controller_spec.rb
Normale Datei
|
@ -0,0 +1,24 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe InvitesControllerCustomWizard, type: :request do
|
||||||
|
fab!(:topic) { Fabricate(:topic) }
|
||||||
|
let(:invite) do
|
||||||
|
Invite.invite_by_email("angus@email.com", topic.user, topic)
|
||||||
|
end
|
||||||
|
let(:template) do
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
|
).read)
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
@controller = InvitesController.new
|
||||||
|
end
|
||||||
|
|
||||||
|
it "redirects a user to wizard after invite if after signup is enabled" do
|
||||||
|
template['after_signup'] = true
|
||||||
|
CustomWizard::Template.save(template, skip_jobs: true)
|
||||||
|
put "/invites/show/#{invite.invite_key}.json"
|
||||||
|
expect(response.parsed_body["redirect_to"]).to eq("/w/super-mega-fun-wizard")
|
||||||
|
end
|
||||||
|
end
|
21
spec/extensions/users_controller_spec.rb
Normale Datei
21
spec/extensions/users_controller_spec.rb
Normale Datei
|
@ -0,0 +1,21 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe CustomWizardUsersController, type: :request do
|
||||||
|
let(:template) do
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
|
).read)
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
@controller = UsersController.new
|
||||||
|
end
|
||||||
|
|
||||||
|
it "redirects a user to wizard after sign up if after signup is enabled" do
|
||||||
|
template['after_signup'] = true
|
||||||
|
CustomWizard::Template.save(template, skip_jobs: true)
|
||||||
|
sign_in(Fabricate(:user))
|
||||||
|
get "/u/account-created"
|
||||||
|
expect(response).to redirect_to("/w/super-mega-fun-wizard")
|
||||||
|
end
|
||||||
|
end
|
21
spec/extensions/wizard_field_spec.rb
Normale Datei
21
spec/extensions/wizard_field_spec.rb
Normale Datei
|
@ -0,0 +1,21 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe CustomWizardFieldExtension do
|
||||||
|
let(:field_hash) do
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/field/field.json"
|
||||||
|
).read).with_indifferent_access
|
||||||
|
end
|
||||||
|
|
||||||
|
it "adds custom field attributes" do
|
||||||
|
field = Wizard::Field.new(field_hash)
|
||||||
|
expect(field.id).to eq("field_id")
|
||||||
|
expect(field.label).to eq("<p>Field Label</p>")
|
||||||
|
expect(field.image).to eq("field_image_url.png")
|
||||||
|
expect(field.description).to eq("Field description")
|
||||||
|
expect(field.required).to eq(true)
|
||||||
|
expect(field.key).to eq("field.locale.key")
|
||||||
|
expect(field.type).to eq("field_type")
|
||||||
|
expect(field.content).to eq([])
|
||||||
|
end
|
||||||
|
end
|
23
spec/extensions/wizard_step_spec.rb
Normale Datei
23
spec/extensions/wizard_step_spec.rb
Normale Datei
|
@ -0,0 +1,23 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe CustomWizardStepExtension do
|
||||||
|
let(:step_hash) do
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/step/step.json"
|
||||||
|
).read).with_indifferent_access
|
||||||
|
end
|
||||||
|
|
||||||
|
it "adds custom step attributes" do
|
||||||
|
step = Wizard::Step.new(step_hash[:id])
|
||||||
|
[
|
||||||
|
:title,
|
||||||
|
:description,
|
||||||
|
:key,
|
||||||
|
:permitted,
|
||||||
|
:permitted_message
|
||||||
|
].each do |attr|
|
||||||
|
step.send("#{attr.to_s}=", step_hash[attr])
|
||||||
|
expect(step.send(attr)).to eq(step_hash[attr])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
10
spec/fixtures/field/field.json
gevendort
Normale Datei
10
spec/fixtures/field/field.json
gevendort
Normale Datei
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"id": "field_id",
|
||||||
|
"label": "Field Label",
|
||||||
|
"image": "field_image_url.png",
|
||||||
|
"description": "Field description",
|
||||||
|
"required": true,
|
||||||
|
"key": "field.locale.key",
|
||||||
|
"type": "field_type",
|
||||||
|
"content": []
|
||||||
|
}
|
4
spec/fixtures/mapper/data.json
gevendort
Normale Datei
4
spec/fixtures/mapper/data.json
gevendort
Normale Datei
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"input_1": "value 1",
|
||||||
|
"input_2": "value 2"
|
||||||
|
}
|
264
spec/fixtures/mapper/inputs.json
gevendort
Normale Datei
264
spec/fixtures/mapper/inputs.json
gevendort
Normale Datei
|
@ -0,0 +1,264 @@
|
||||||
|
{
|
||||||
|
"assignment": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output_type": "group",
|
||||||
|
"output_connector": "set",
|
||||||
|
"output": [
|
||||||
|
13
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"assignment_text": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set",
|
||||||
|
"output": "Value"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"assignment_user_field": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output_type": "user_field",
|
||||||
|
"output_connector": "set",
|
||||||
|
"output": "name"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"assignment_user_field_options": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output_type": "user_field_options",
|
||||||
|
"output_connector": "set",
|
||||||
|
"output": "user_field_3"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"assignment_wizard_field": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output_type": "wizard_field",
|
||||||
|
"output_connector": "set",
|
||||||
|
"output": "input_1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"assignment_wizard_action": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output_type": "wizard_action",
|
||||||
|
"output_connector": "set",
|
||||||
|
"output": "input_2"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interpolate_user_field": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set",
|
||||||
|
"output": "Name: u{name}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interpolate_wizard_field": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set",
|
||||||
|
"output": "Input 1: w{input_1}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interpolate_timestamp": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set",
|
||||||
|
"output": "Time: v{time}"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validation": [
|
||||||
|
{
|
||||||
|
"type": "validation",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "input_1",
|
||||||
|
"key_type": "wizard_field",
|
||||||
|
"value": "value 1",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "equal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 1,
|
||||||
|
"key": "input_2",
|
||||||
|
"key_type": "wizard_field",
|
||||||
|
"value": "value 2",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "equal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"association": [
|
||||||
|
{
|
||||||
|
"type": "association",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "choice1",
|
||||||
|
"key_type": "text",
|
||||||
|
"value": "Choice 1",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "equal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 1,
|
||||||
|
"key": "choice2",
|
||||||
|
"key_type": "text",
|
||||||
|
"value": "Choice 2",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "association"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 2,
|
||||||
|
"key": "choice3",
|
||||||
|
"key_type": "text",
|
||||||
|
"value": "Choice 3",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "association"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"conditional": [
|
||||||
|
{
|
||||||
|
"type": "conditional",
|
||||||
|
"output": "true",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "then",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "name",
|
||||||
|
"key_type": "user_field",
|
||||||
|
"value": "Angus",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "equal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"conditional_multiple_pairs": [
|
||||||
|
{
|
||||||
|
"type": "conditional",
|
||||||
|
"output": "true",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "then",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "name",
|
||||||
|
"key_type": "user_field",
|
||||||
|
"value": "Angus",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "equal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 1,
|
||||||
|
"key": "email",
|
||||||
|
"key_type": "user_field",
|
||||||
|
"value": "angus@email.com",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "equal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"greater_than_pair": [
|
||||||
|
{
|
||||||
|
"type": "validation",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "trust_level",
|
||||||
|
"key_type": "user_field",
|
||||||
|
"value": "2",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "greater"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"less_than_pair": [
|
||||||
|
{
|
||||||
|
"type": "validation",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "trust_level",
|
||||||
|
"key_type": "user_field",
|
||||||
|
"value": "2",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "less"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"greater_than_or_equal_pair": [
|
||||||
|
{
|
||||||
|
"type": "validation",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "trust_level",
|
||||||
|
"key_type": "user_field",
|
||||||
|
"value": "1",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "greater_or_equal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"less_than_or_equal_pair": [
|
||||||
|
{
|
||||||
|
"type": "validation",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "trust_level",
|
||||||
|
"key_type": "user_field",
|
||||||
|
"value": "3",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "less_or_equal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"regex_pair": [
|
||||||
|
{
|
||||||
|
"type": "validation",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "email",
|
||||||
|
"key_type": "user_field",
|
||||||
|
"value": "@email.com",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "regex"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"shorthand_pair": [
|
||||||
|
{
|
||||||
|
"type": "validation",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "bio_raw",
|
||||||
|
"key_type": "user_field",
|
||||||
|
"value": "present",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "is"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
18
spec/fixtures/step/required_data.json
gevendort
Normale Datei
18
spec/fixtures/step/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
spec/fixtures/step/step.json
gevendort
Normale Datei
10
spec/fixtures/step/step.json
gevendort
Normale Datei
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"id": "step_1",
|
||||||
|
"title": "Text",
|
||||||
|
"description": "Step description",
|
||||||
|
"image": "step_image_url.png",
|
||||||
|
"key": "step.locale.key",
|
||||||
|
"fields": [],
|
||||||
|
"required_data": [],
|
||||||
|
"permitted": []
|
||||||
|
}
|
521
spec/fixtures/wizard.json
gevendort
521
spec/fixtures/wizard.json
gevendort
|
@ -1,49 +1,516 @@
|
||||||
{
|
{
|
||||||
"id": "welcome",
|
"id": "super_mega_fun_wizard",
|
||||||
"name": "Welcome",
|
"name": "Super Mega Fun Wizard",
|
||||||
"background": "#006da3",
|
"background": "#333333",
|
||||||
"save_submissions": true,
|
"save_submissions": true,
|
||||||
"multiple_submissions": true,
|
"multiple_submissions": true,
|
||||||
"after_signup": true,
|
"after_signup": false,
|
||||||
"min_trust": 1,
|
"prompt_completion": true,
|
||||||
"theme_id": 4,
|
"theme_id": 2,
|
||||||
"steps": [
|
"steps": [
|
||||||
{
|
{
|
||||||
"id": "welcome",
|
"id": "step_1",
|
||||||
"title": "Welcome to Pavilion",
|
"title": "Text",
|
||||||
"raw_description": "Hey there, thanks for signing up.\n\nWe're Pavilion, an international freelancer cooperative that specialises in online communities.\n\nThis site is our own community, where we work with our clients, users of our open source work and our broader community.\n\n",
|
"raw_description": "Text inputs!",
|
||||||
"description": "<p>Hey there, thanks for signing up.</p>\n<p>We’re Pavilion, an international freelancer cooperative that specialises in online communities.</p>\n<p>This site is our own community, where we work with our clients, users of our open source work and our broader community.</p>",
|
|
||||||
"fields": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"id": "name",
|
"id": "step_1_field_1",
|
||||||
|
"label": "Text",
|
||||||
|
"description": "Text field description.",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"label": "Name"
|
"min_length": "3",
|
||||||
|
"prefill": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "I am prefilled",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "step_1_field_2",
|
||||||
|
"label": "Textarea",
|
||||||
|
"type": "textarea",
|
||||||
|
"min_length": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "step_1_field_3",
|
||||||
|
"label": "Composer",
|
||||||
|
"type": "composer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "step_1_field_4",
|
||||||
|
"label": "I'm only text",
|
||||||
|
"description": "",
|
||||||
|
"type": "text_only"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "<p>Text inputs!</p>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "step_2",
|
||||||
|
"title": "Values",
|
||||||
|
"raw_description": "Because I couldn't think of another name for this step :)",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"id": "step_2_field_1",
|
||||||
|
"label": "Date",
|
||||||
|
"type": "date",
|
||||||
|
"format": "YYYY-MM-DD"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "step_2_field_2",
|
||||||
|
"label": "Time",
|
||||||
|
"type": "time",
|
||||||
|
"format": "HH:mm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "step_2_field_3",
|
||||||
|
"label": "Date & Time",
|
||||||
|
"type": "date_time",
|
||||||
|
"format": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "step_2_field_4",
|
||||||
|
"label": "Number",
|
||||||
|
"type": "number"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "step_2_field_5",
|
||||||
|
"label": "Checkbox",
|
||||||
|
"type": "checkbox"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "step_2_field_7",
|
||||||
|
"label": "Upload",
|
||||||
|
"type": "upload",
|
||||||
|
"file_types": ".jpg,.png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "<p>Because I couldn’t think of another name for this step <img src=\"/images/emoji/twitter/slight_smile.png?v=9\" title=\":slight_smile:\" class=\"emoji\" alt=\":slight_smile:\"></p>"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "step_3",
|
||||||
|
"title": "Combo-boxes",
|
||||||
|
"raw_description": "Unfortunately not the edible type :sushi: ",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"id": "step_3_field_1",
|
||||||
|
"label": "Custom Dropdown",
|
||||||
|
"type": "dropdown",
|
||||||
|
"content": [
|
||||||
|
{
|
||||||
|
"type": "association",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "choice1",
|
||||||
|
"key_type": "text",
|
||||||
|
"value": "Choice 1",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "equal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 1,
|
||||||
|
"key": "choice2",
|
||||||
|
"key_type": "text",
|
||||||
|
"value": "Choice 2",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "association"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index": 2,
|
||||||
|
"key": "choice3",
|
||||||
|
"key_type": "text",
|
||||||
|
"value": "Choice 3",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "association"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "step_3_field_2",
|
||||||
|
"label": "Tag",
|
||||||
|
"type": "tag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "step_3_field_3",
|
||||||
|
"label": "Category",
|
||||||
|
"type": "category",
|
||||||
|
"limit": 1,
|
||||||
|
"property": "id"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "step_3_field_4",
|
||||||
|
"label": "Group",
|
||||||
|
"type": "group"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "step_3_field_5",
|
||||||
|
"label": "User Selector",
|
||||||
|
"description": "",
|
||||||
|
"type": "user_selector"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "<p>Unfortunately not the edible type <img src=\"/images/emoji/twitter/sushi.png?v=9\" title=\":sushi:\" class=\"emoji\" alt=\":sushi:\"></p>"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"id": "action_9",
|
||||||
|
"run_after": "step_1",
|
||||||
|
"type": "create_group",
|
||||||
|
"title": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "New Group Member",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"custom_fields": [
|
||||||
|
{
|
||||||
|
"type": "association",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "group_custom_field",
|
||||||
|
"key_type": "text",
|
||||||
|
"value": "step_3_field_1",
|
||||||
|
"value_type": "wizard_field",
|
||||||
|
"connector": "association"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "step_1_field_1",
|
||||||
|
"output_type": "wizard_field",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"full_name": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "step_1_field_1",
|
||||||
|
"output_type": "wizard_field",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"usernames": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output_type": "user",
|
||||||
|
"output_connector": "set",
|
||||||
|
"output": [
|
||||||
|
"angus1"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"owner_usernames": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output_type": "user",
|
||||||
|
"output_connector": "set",
|
||||||
|
"output": [
|
||||||
|
"angus"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"grant_trust_level": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "3",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mentionable_level": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "1",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"messageable_level": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "2",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"visibility_level": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "3",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"members_visibility_level": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "99",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "about_you",
|
"id": "action_6",
|
||||||
"title": "Tell us about you",
|
"run_after": "step_1",
|
||||||
"raw_description": "We'd like to know a little more about you. Add a your name and your website below. This will update your user profile.",
|
"type": "add_to_group",
|
||||||
"description": "<p>We’d like to know a little more about you. Add a your name and your website below. This will update your user profile.</p>",
|
"group": [
|
||||||
"fields": [
|
|
||||||
{
|
{
|
||||||
"id": "website",
|
"type": "assignment",
|
||||||
"label": "Website",
|
"output": "action_9",
|
||||||
"type": "text"
|
"output_type": "wizard_action",
|
||||||
|
"output_connector": "set"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"actions": [
|
},
|
||||||
|
{
|
||||||
|
"id": "action_8",
|
||||||
|
"run_after": "step_1",
|
||||||
|
"type": "create_category",
|
||||||
|
"custom_fields": [
|
||||||
{
|
{
|
||||||
"id": "update_profile",
|
"type": "association",
|
||||||
"type": "update_profile",
|
"pairs": [
|
||||||
"profile_updates": [
|
|
||||||
{
|
{
|
||||||
"key": "name",
|
"index": 0,
|
||||||
"value": "name"
|
"key": "category_custom_field",
|
||||||
|
"key_type": "text",
|
||||||
|
"value": "CC Val",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "association"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
],
|
||||||
|
"name": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "step_1_field_1",
|
||||||
|
"output_type": "wizard_field",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"slug": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "step_1_field_1",
|
||||||
|
"output_type": "wizard_field",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"type": "association",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "action_9",
|
||||||
|
"key_type": "wizard_action",
|
||||||
|
"value": "2",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "association"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "action_5",
|
||||||
|
"run_after": "step_1",
|
||||||
|
"type": "watch_categories",
|
||||||
|
"notification_level": "tracking",
|
||||||
|
"wizard_user": true,
|
||||||
|
"categories": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "action_8",
|
||||||
|
"output_type": "wizard_action",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mute_remainder": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "true",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "action_1",
|
||||||
|
"run_after": "step_3",
|
||||||
|
"type": "create_topic",
|
||||||
|
"skip_redirect": true,
|
||||||
|
"post": "step_1_field_2",
|
||||||
|
"title": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "step_1_field_1",
|
||||||
|
"output_type": "wizard_field",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"category": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "step_3_field_3",
|
||||||
|
"output_type": "wizard_field",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "step_3_field_2",
|
||||||
|
"output_type": "wizard_field",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"custom_fields": [
|
||||||
|
{
|
||||||
|
"type": "association",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "custom_field_1",
|
||||||
|
"key_type": "text",
|
||||||
|
"value": "title",
|
||||||
|
"value_type": "user_field",
|
||||||
|
"connector": "association"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"visible": [
|
||||||
|
{
|
||||||
|
"type": "conditional",
|
||||||
|
"output": "true",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "then",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "name",
|
||||||
|
"key_type": "user_field",
|
||||||
|
"value": "Angus",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "equal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "action_4",
|
||||||
|
"run_after": "step_2",
|
||||||
|
"type": "update_profile",
|
||||||
|
"profile_updates": [
|
||||||
|
{
|
||||||
|
"type": "association",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "profile_background",
|
||||||
|
"key_type": "user_field",
|
||||||
|
"value": "step_2_field_7",
|
||||||
|
"value_type": "wizard_field",
|
||||||
|
"connector": "association"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "action_2",
|
||||||
|
"run_after": "step_2",
|
||||||
|
"type": "send_message",
|
||||||
|
"post_builder": true,
|
||||||
|
"post_template": "I will interpolate some wizard fields w{step_1_field_1} w{step_1_field_2}",
|
||||||
|
"title": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "Message title",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"recipient": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output_type": "user",
|
||||||
|
"output_connector": "set",
|
||||||
|
"output": [
|
||||||
|
"angus1"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "action_3",
|
||||||
|
"run_after": "step_2",
|
||||||
|
"type": "open_composer",
|
||||||
|
"post_builder": true,
|
||||||
|
"post_template": "I am interpolating some user fields u{name} u{username} u{email}",
|
||||||
|
"title": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "Title of the composer topic",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"category": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "action_8",
|
||||||
|
"output_type": "wizard_action",
|
||||||
|
"output_connector": "set",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"key": "step_2_field_5",
|
||||||
|
"key_type": "wizard_field",
|
||||||
|
"value": "true",
|
||||||
|
"value_type": "text",
|
||||||
|
"connector": "is"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "tag1",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "action_10",
|
||||||
|
"run_after": "wizard_completion",
|
||||||
|
"type": "route_to",
|
||||||
|
"url": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "https://google.com",
|
||||||
|
"output_type": "text",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
4
spec/fixtures/wizard/after_time.json
gevendort
Normale Datei
4
spec/fixtures/wizard/after_time.json
gevendort
Normale Datei
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"after_time": true,
|
||||||
|
"after_time_scheduled": "2020-11-20T00:59:00.000Z"
|
||||||
|
}
|
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
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
37
spec/jobs/clear_after_time_wizard_spec.rb
Normale Datei
37
spec/jobs/clear_after_time_wizard_spec.rb
Normale Datei
|
@ -0,0 +1,37 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe Jobs::ClearAfterTimeWizard do
|
||||||
|
fab!(:user1) { Fabricate(:user) }
|
||||||
|
fab!(:user2) { Fabricate(:user) }
|
||||||
|
fab!(:user3) { Fabricate(:user) }
|
||||||
|
|
||||||
|
let(:template) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
|
).read).with_indifferent_access
|
||||||
|
}
|
||||||
|
let(:after_time) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/after_time.json"
|
||||||
|
).read).with_indifferent_access
|
||||||
|
}
|
||||||
|
|
||||||
|
it "clears wizard redirect for all users " do
|
||||||
|
after_time_template = template.dup
|
||||||
|
after_time_template["after_time"] = after_time['after_time']
|
||||||
|
after_time_template["after_time_scheduled"] = after_time['after_time_scheduled']
|
||||||
|
|
||||||
|
CustomWizard::Template.save(after_time_template)
|
||||||
|
|
||||||
|
described_class.new.execute(wizard_id: 'super_mega_fun_wizard')
|
||||||
|
|
||||||
|
expect(
|
||||||
|
UserCustomField.where("
|
||||||
|
name = 'redirect_to_wizard' AND
|
||||||
|
value = 'super_mega_fun_wizard'
|
||||||
|
").exists?
|
||||||
|
).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
42
spec/jobs/set_after_time_wizard_spec.rb
Normale Datei
42
spec/jobs/set_after_time_wizard_spec.rb
Normale Datei
|
@ -0,0 +1,42 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe Jobs::SetAfterTimeWizard do
|
||||||
|
fab!(:user1) { Fabricate(:user) }
|
||||||
|
fab!(:user2) { Fabricate(:user) }
|
||||||
|
fab!(:user3) { Fabricate(:user) }
|
||||||
|
|
||||||
|
let(:template) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
|
).read).with_indifferent_access
|
||||||
|
}
|
||||||
|
let(:after_time) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/after_time.json"
|
||||||
|
).read).with_indifferent_access
|
||||||
|
}
|
||||||
|
|
||||||
|
it "sets wizard redirect for all users " do
|
||||||
|
after_time_template = template.dup
|
||||||
|
after_time_template["after_time"] = after_time['after_time']
|
||||||
|
after_time_template["after_time_scheduled"] = after_time['after_time_scheduled']
|
||||||
|
|
||||||
|
CustomWizard::Template.save(after_time_template)
|
||||||
|
|
||||||
|
messages = MessageBus.track_publish("/redirect_to_wizard") do
|
||||||
|
described_class.new.execute(wizard_id: 'super_mega_fun_wizard')
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(
|
||||||
|
UserCustomField.where(
|
||||||
|
name: 'redirect_to_wizard',
|
||||||
|
value: 'super_mega_fun_wizard'
|
||||||
|
).length
|
||||||
|
).to eq(3)
|
||||||
|
|
||||||
|
expect(messages.first.data).to eq("super_mega_fun_wizard")
|
||||||
|
expect(messages.first.user_ids).to match_array([user1.id,user2.id,user3.id])
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,6 +3,8 @@ require 'simplecov'
|
||||||
SimpleCov.configure do
|
SimpleCov.configure do
|
||||||
add_filter do |src|
|
add_filter do |src|
|
||||||
src.filename !~ /discourse-custom-wizard/ ||
|
src.filename !~ /discourse-custom-wizard/ ||
|
||||||
src.filename =~ /spec/
|
src.filename =~ /spec/ ||
|
||||||
|
src.filename =~ /db/ ||
|
||||||
|
src.filename =~ /api/ ## API features are currently experimental
|
||||||
end
|
end
|
||||||
end
|
end
|
22
spec/requests/custom_wizard/admin/logs_controller_spec.rb
Normale Datei
22
spec/requests/custom_wizard/admin/logs_controller_spec.rb
Normale Datei
|
@ -0,0 +1,22 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe CustomWizard::AdminLogsController do
|
||||||
|
fab!(:admin_user) { Fabricate(:user, admin: true) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
CustomWizard::Log.create("First log message")
|
||||||
|
CustomWizard::Log.create("Second log message")
|
||||||
|
CustomWizard::Log.create("Third log message")
|
||||||
|
sign_in(admin_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a list of logs" do
|
||||||
|
get "/admin/wizards/logs.json"
|
||||||
|
expect(response.parsed_body.length).to eq(3)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "paginates" do
|
||||||
|
get "/admin/wizards/logs.json", params: { page: 1, limit: 2 }
|
||||||
|
expect(response.parsed_body.length).to eq(1)
|
||||||
|
end
|
||||||
|
end
|
45
spec/requests/custom_wizard/admin/submissions_controller_spec.rb
Normale Datei
45
spec/requests/custom_wizard/admin/submissions_controller_spec.rb
Normale Datei
|
@ -0,0 +1,45 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe CustomWizard::AdminSubmissionsController do
|
||||||
|
fab!(:admin_user) {Fabricate(:user, admin: true)}
|
||||||
|
fab!(:user1) {Fabricate(:user)}
|
||||||
|
fab!(:user2) {Fabricate(:user)}
|
||||||
|
|
||||||
|
let(:template) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
|
).read)
|
||||||
|
}
|
||||||
|
|
||||||
|
before do
|
||||||
|
CustomWizard::Template.save(template, skip_jobs: true)
|
||||||
|
CustomWizard::Wizard.set_submissions(template['id'], user1,
|
||||||
|
step_1_field_1: "I am a user1's submission"
|
||||||
|
)
|
||||||
|
CustomWizard::Wizard.set_submissions(template['id'], user2,
|
||||||
|
step_1_field_1: "I am a user2's submission"
|
||||||
|
)
|
||||||
|
sign_in(admin_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a basic list of wizards" do
|
||||||
|
get "/admin/wizards/submissions.json"
|
||||||
|
expect(response.parsed_body.length).to eq(1)
|
||||||
|
expect(response.parsed_body.first['id']).to eq(template['id'])
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the all user's submissions for a wizard" do
|
||||||
|
get "/admin/wizards/submissions/#{template['id']}.json"
|
||||||
|
expect(response.parsed_body['submissions'].length).to eq(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns the all user's submissions for a wizard" do
|
||||||
|
get "/admin/wizards/submissions/#{template['id']}.json"
|
||||||
|
expect(response.parsed_body['submissions'].length).to eq(2)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "downloads all user submissions" do
|
||||||
|
get "/admin/wizards/submissions/#{template['id']}/download"
|
||||||
|
expect(response.parsed_body.length).to eq(2)
|
||||||
|
end
|
||||||
|
end
|
52
spec/requests/custom_wizard/admin/transfer_controller_spec.rb
Normale Datei
52
spec/requests/custom_wizard/admin/transfer_controller_spec.rb
Normale Datei
|
@ -0,0 +1,52 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe CustomWizard::AdminTransferController do
|
||||||
|
fab!(:admin_user) { Fabricate(:user, admin: true) }
|
||||||
|
|
||||||
|
let(:template) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
|
).read)
|
||||||
|
}
|
||||||
|
|
||||||
|
before do
|
||||||
|
sign_in(admin_user)
|
||||||
|
|
||||||
|
CustomWizard::Template.save(template, skip_jobs: true)
|
||||||
|
|
||||||
|
template_2 = template.dup
|
||||||
|
template_2["id"] = 'super_mega_fun_wizard_2'
|
||||||
|
CustomWizard::Template.save(template_2, skip_jobs: true)
|
||||||
|
|
||||||
|
template_3 = template.dup
|
||||||
|
template_3["id"] = 'super_mega_fun_wizard_3'
|
||||||
|
template_3["after_signup"] = true
|
||||||
|
CustomWizard::Template.save(template_3, skip_jobs: true)
|
||||||
|
|
||||||
|
@template_array = [template, template_2, template_3]
|
||||||
|
|
||||||
|
FileUtils.mkdir_p(file_from_fixtures_tmp_folder) unless Dir.exists?(file_from_fixtures_tmp_folder)
|
||||||
|
@tmp_file_path = File.join(file_from_fixtures_tmp_folder, SecureRandom.hex << 'wizards.json')
|
||||||
|
File.write(@tmp_file_path, @template_array.to_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'exports all the wizard templates' do
|
||||||
|
get '/admin/wizards/transfer/export.json', params: {
|
||||||
|
wizards: [
|
||||||
|
'super_mega_fun_wizard',
|
||||||
|
'super_mega_fun_wizard_2',
|
||||||
|
'super_mega_fun_wizard_3'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
expect(response.parsed_body).to match_array(@template_array)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'imports wizard a template' do
|
||||||
|
post '/admin/wizards/transfer/import.json', params: {
|
||||||
|
file: fixture_file_upload(File.open(@tmp_file_path))
|
||||||
|
}
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
expect(response.parsed_body['success']).to eq(@template_array.map { |t| t['id'] })
|
||||||
|
end
|
||||||
|
end
|
66
spec/requests/custom_wizard/admin/wizard_controller_spec.rb
Normale Datei
66
spec/requests/custom_wizard/admin/wizard_controller_spec.rb
Normale Datei
|
@ -0,0 +1,66 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe CustomWizard::AdminWizardController do
|
||||||
|
fab!(:admin_user) {Fabricate(:user, admin: true)}
|
||||||
|
fab!(:user1) {Fabricate(:user)}
|
||||||
|
fab!(:user2) {Fabricate(:user)}
|
||||||
|
|
||||||
|
let(:template) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
|
).read)
|
||||||
|
}
|
||||||
|
|
||||||
|
before do
|
||||||
|
CustomWizard::Template.save(template, skip_jobs: true)
|
||||||
|
|
||||||
|
template_2 = template.dup
|
||||||
|
template_2["id"] = 'super_mega_fun_wizard_2'
|
||||||
|
template_2["permitted"] = template_2['permitted']
|
||||||
|
CustomWizard::Template.save(template_2, skip_jobs: true)
|
||||||
|
|
||||||
|
template_3 = template.dup
|
||||||
|
template_3["id"] = 'super_mega_fun_wizard_3'
|
||||||
|
template_3["after_signup"] = true
|
||||||
|
CustomWizard::Template.save(template_3, skip_jobs: true)
|
||||||
|
|
||||||
|
sign_in(admin_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a basic list of wizard templates and wizard field types" do
|
||||||
|
get "/admin/wizards/wizard.json"
|
||||||
|
expect(
|
||||||
|
response.parsed_body['wizard_list'].map { |w| w['id'] }
|
||||||
|
).to match_array(['super_mega_fun_wizard', 'super_mega_fun_wizard_2', 'super_mega_fun_wizard_3'])
|
||||||
|
expect(
|
||||||
|
response.parsed_body['field_types'].keys
|
||||||
|
).to eq(CustomWizard::Field.types.keys.map(&:to_s))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns a wizard template" do
|
||||||
|
get "/admin/wizards/wizard/#{template['id']}.json"
|
||||||
|
expect(response.parsed_body['id']).to eq(template['id'])
|
||||||
|
expect(response.parsed_body['steps'].length).to eq(3)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "removes wizard templates" do
|
||||||
|
delete "/admin/wizards/wizard/#{template['id']}.json"
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
expect(CustomWizard::Template.exists?(template['id'])).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "saves wizard templates" do
|
||||||
|
template_updated = template.dup
|
||||||
|
template_updated['name'] = "Super Mega Fun Wizard 2"
|
||||||
|
template_updated['multiple_submissions'] = false
|
||||||
|
template_updated['steps'][0]['fields'][0]['label'] = "Text 2"
|
||||||
|
|
||||||
|
put "/admin/wizards/wizard/#{template['id']}.json", params: { wizard: template_updated }
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
|
||||||
|
updated_template = CustomWizard::Template.find('super_mega_fun_wizard')
|
||||||
|
expect(updated_template['name']).to eq("Super Mega Fun Wizard 2")
|
||||||
|
expect(updated_template['multiple_submissions']).to eq("false")
|
||||||
|
expect(updated_template['steps'][0]['fields'][0]['label']).to eq("Text 2")
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,5 +0,0 @@
|
||||||
require 'rails_helper'
|
|
||||||
|
|
||||||
describe CustomWizard::AdminController do
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,5 +1,61 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
describe ApplicationController do
|
describe ApplicationController do
|
||||||
|
fab!(:user) {
|
||||||
|
Fabricate(
|
||||||
|
:user,
|
||||||
|
username: 'angus',
|
||||||
|
email: "angus@email.com",
|
||||||
|
trust_level: TrustLevel[3]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
before do
|
||||||
|
CustomWizard::Template.save(
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
|
).read),
|
||||||
|
skip_jobs: true)
|
||||||
|
@template = CustomWizard::Template.find('super_mega_fun_wizard')
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with signed in user" do
|
||||||
|
before do
|
||||||
|
sign_in(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "who is required to complete wizard" do
|
||||||
|
before do
|
||||||
|
user.custom_fields['redirect_to_wizard'] = 'super_mega_fun_wizard'
|
||||||
|
user.save_custom_fields(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "redirects if user is required to complete a wizard" do
|
||||||
|
get "/"
|
||||||
|
expect(response).to redirect_to("/w/super-mega-fun-wizard")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "saves original destination of user" do
|
||||||
|
get '/', headers: { 'REFERER' => "/t/2" }
|
||||||
|
expect(
|
||||||
|
CustomWizard::Wizard.submissions(@template['id'], user)
|
||||||
|
.first['redirect_to']
|
||||||
|
).to eq("/t/2")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "who is not required to complete wizard" do
|
||||||
|
it "does nothing" do
|
||||||
|
get "/"
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with guest" do
|
||||||
|
it "does nothing" do
|
||||||
|
get "/"
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
34
spec/requests/custom_wizard/steps_controller_spec.rb
Normale Datei
34
spec/requests/custom_wizard/steps_controller_spec.rb
Normale Datei
|
@ -0,0 +1,34 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe CustomWizard::StepsController do
|
||||||
|
fab!(:user) {
|
||||||
|
Fabricate(
|
||||||
|
:user,
|
||||||
|
username: 'angus',
|
||||||
|
email: "angus@email.com",
|
||||||
|
trust_level: TrustLevel[3]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
before do
|
||||||
|
CustomWizard::Template.save(
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
|
).read),
|
||||||
|
skip_jobs: true)
|
||||||
|
sign_in(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'performs a step update' do
|
||||||
|
put '/w/super-mega-fun-wizard/steps/step_1.json', params: {
|
||||||
|
fields: {
|
||||||
|
step_1_field_1: "Text input"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
|
||||||
|
wizard = CustomWizard::Builder.new("super_mega_fun_wizard", user).build
|
||||||
|
expect(wizard.current_submission['step_1_field_1']).to eq("Text input")
|
||||||
|
expect(wizard.start.id).to eq("step_2")
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,31 +1,63 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
describe CustomWizard::WizardController do
|
describe CustomWizard::WizardController do
|
||||||
it 'returns a wizard if enabled' do
|
fab!(:user) {
|
||||||
|
Fabricate(
|
||||||
|
:user,
|
||||||
|
username: 'angus',
|
||||||
|
email: "angus@email.com",
|
||||||
|
trust_level: TrustLevel[3]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
before do
|
||||||
|
CustomWizard::Template.save(
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
|
).read),
|
||||||
|
skip_jobs: true)
|
||||||
|
@template = CustomWizard::Template.find("super_mega_fun_wizard")
|
||||||
|
sign_in(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns a disabled message if disabled' do
|
context 'plugin disabled' do
|
||||||
|
before do
|
||||||
end
|
SiteSetting.custom_wizard_enabled = false
|
||||||
|
end
|
||||||
it 'returns a missing message if no wizard exists' do
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'returns a custom wizard theme' do
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'updates the page title' do
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'skips a wizard if user is allowed to skip' do
|
|
||||||
|
|
||||||
|
it 'redirects to root' do
|
||||||
|
get '/w/super-mega-fun-wizard', xhr: true
|
||||||
|
expect(response).to redirect_to("/")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns wizard' do
|
||||||
|
get '/w/super-mega-fun-wizard.json'
|
||||||
|
expect(response.parsed_body["id"]).to eq("super_mega_fun_wizard")
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns missing message if no wizard exists' do
|
||||||
|
get '/w/super-mega-fun-wizards.json'
|
||||||
|
expect(response.parsed_body["error"]).to eq("We couldn't find a wizard at that address.")
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'skips a wizard if user is allowed to skip' do
|
||||||
|
put '/w/super-mega-fun-wizard/skip.json'
|
||||||
|
expect(response.status).to eq(200)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns a no skip message if user is not allowed to skip' do
|
it 'returns a no skip message if user is not allowed to skip' do
|
||||||
|
@template['required'] = 'true'
|
||||||
|
CustomWizard::Template.save(@template)
|
||||||
|
put '/w/super-mega-fun-wizard/skip.json'
|
||||||
|
expect(response.parsed_body['error']).to eq("Wizard can't be skipped")
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'skip response contains a redirect_to if in users submissions' do
|
||||||
|
CustomWizard::Wizard.set_submissions(@template['id'], user,
|
||||||
|
redirect_to: '/t/2'
|
||||||
|
)
|
||||||
|
put '/w/super-mega-fun-wizard/skip.json'
|
||||||
|
expect(response.parsed_body['redirect_to']).to eq('/t/2')
|
||||||
end
|
end
|
||||||
end
|
end
|
21
spec/serializers/custom_wizard/basic_wizard_serializer_spec.rb
Normale Datei
21
spec/serializers/custom_wizard/basic_wizard_serializer_spec.rb
Normale Datei
|
@ -0,0 +1,21 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe CustomWizard::BasicWizardSerializer do
|
||||||
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
|
it 'should return basic wizard attributes' do
|
||||||
|
CustomWizard::Template.save(
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
|
).read),
|
||||||
|
skip_jobs: true)
|
||||||
|
json = CustomWizard::BasicWizardSerializer.new(
|
||||||
|
CustomWizard::Builder.new("super_mega_fun_wizard", user).build,
|
||||||
|
scope: Guardian.new(user)
|
||||||
|
).as_json
|
||||||
|
expect(json[:basic_wizard][:id]).to eq("super_mega_fun_wizard")
|
||||||
|
expect(json[:basic_wizard][:name]).to eq("Super Mega Fun Wizard")
|
||||||
|
end
|
||||||
|
end
|
19
spec/serializers/custom_wizard/log_serializer_spec.rb
Normale Datei
19
spec/serializers/custom_wizard/log_serializer_spec.rb
Normale Datei
|
@ -0,0 +1,19 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe CustomWizard::LogSerializer do
|
||||||
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
|
it 'should return log attributes' do
|
||||||
|
CustomWizard::Log.create("First log message")
|
||||||
|
CustomWizard::Log.create("Second log message")
|
||||||
|
|
||||||
|
json_array = ActiveModel::ArraySerializer.new(
|
||||||
|
CustomWizard::Log.list(0),
|
||||||
|
each_serializer: CustomWizard::LogSerializer
|
||||||
|
).as_json
|
||||||
|
expect(json_array.length).to eq(2)
|
||||||
|
expect(json_array[0][:message]).to eq("Second log message")
|
||||||
|
end
|
||||||
|
end
|
37
spec/serializers/custom_wizard/wizard_field_serializer_spec.rb
Normale Datei
37
spec/serializers/custom_wizard/wizard_field_serializer_spec.rb
Normale Datei
|
@ -0,0 +1,37 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe CustomWizard::FieldSerializer do
|
||||||
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
CustomWizard::Template.save(
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
|
).read),
|
||||||
|
skip_jobs: true)
|
||||||
|
@wizard = CustomWizard::Builder.new("super_mega_fun_wizard", user).build
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return basic field attributes" do
|
||||||
|
json_array = ActiveModel::ArraySerializer.new(
|
||||||
|
@wizard.steps.first.fields,
|
||||||
|
each_serializer: CustomWizard::FieldSerializer,
|
||||||
|
scope: Guardian.new(user)
|
||||||
|
).as_json
|
||||||
|
expect(json_array.length).to eq(4)
|
||||||
|
expect(json_array[0][:label]).to eq("<p>Text</p>")
|
||||||
|
expect(json_array[0][:description]).to eq("Text field description.")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return optional field attributes" do
|
||||||
|
json_array = ActiveModel::ArraySerializer.new(
|
||||||
|
@wizard.steps.second.fields,
|
||||||
|
each_serializer: CustomWizard::FieldSerializer,
|
||||||
|
scope: Guardian.new(user)
|
||||||
|
).as_json
|
||||||
|
expect(json_array[0][:format]).to eq("YYYY-MM-DD")
|
||||||
|
expect(json_array[5][:file_types]).to eq(".jpg,.png")
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,48 +2,85 @@
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
describe CustomWizardSerializer do
|
describe CustomWizard::WizardSerializer do
|
||||||
fab!(:user) { Fabricate(:user) }
|
fab!(:user) { Fabricate(:user) }
|
||||||
fab!(:category) { Fabricate(:category) }
|
fab!(:category) { Fabricate(:category) }
|
||||||
|
|
||||||
let!(:template) do
|
before do
|
||||||
JSON.parse(File.open(
|
CustomWizard::Template.save(
|
||||||
"#{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"
|
||||||
|
).read),
|
||||||
|
skip_jobs: true)
|
||||||
|
@template = CustomWizard::Template.find('super_mega_fun_wizard')
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:category_field) {{"id": "category","type": "category","limit": "1","label": "Category"}}
|
|
||||||
|
|
||||||
def build_wizard(t = template, u = user, build_opts = {}, params = {})
|
|
||||||
CustomWizard::Wizard.add_wizard(t)
|
|
||||||
CustomWizard::Builder.new('welcome', u).build(build_opts, params)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should return the wizard attributes' do
|
it 'should return the wizard attributes' do
|
||||||
json = CustomWizardSerializer.new(build_wizard, scope: Guardian.new(user)).as_json
|
json = CustomWizard::WizardSerializer.new(
|
||||||
expect(json[:custom_wizard][:id]).to eq("welcome")
|
CustomWizard::Builder.new(@template[:id], user).build,
|
||||||
expect(json[:custom_wizard][:name]).to eq("Welcome")
|
scope: Guardian.new(user)
|
||||||
expect(json[:custom_wizard][:background]).to eq("#006da3")
|
).as_json
|
||||||
expect(json[:custom_wizard][:required]).to eq(false)
|
expect(json[:wizard][:id]).to eq("super_mega_fun_wizard")
|
||||||
expect(json[:custom_wizard][:min_trust]).to eq(1)
|
expect(json[:wizard][:name]).to eq("Super Mega Fun Wizard")
|
||||||
|
expect(json[:wizard][:background]).to eq("#333333")
|
||||||
|
expect(json[:wizard][:required]).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return the wizard steps' do
|
||||||
|
json = CustomWizard::WizardSerializer.new(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build,
|
||||||
|
scope: Guardian.new(user)
|
||||||
|
).as_json
|
||||||
|
expect(json[:wizard][:steps].length).to eq(3)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should return the wizard user attributes" do
|
it "should return the wizard user attributes" do
|
||||||
json = CustomWizardSerializer.new(build_wizard, scope: Guardian.new(user)).as_json
|
json = CustomWizard::WizardSerializer.new(
|
||||||
expect(json[:custom_wizard][:permitted]).to eq(true)
|
CustomWizard::Builder.new(@template[:id], user).build,
|
||||||
expect(json[:custom_wizard][:user]).to eq(BasicUserSerializer.new(user, root: false).as_json)
|
scope: Guardian.new(user)
|
||||||
|
).as_json
|
||||||
|
expect(
|
||||||
|
json[:wizard][:user]
|
||||||
|
).to eq(BasicUserSerializer.new(user, root: false).as_json)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should not return category attributes if there are no category fields" do
|
it "should not return categories if there are no category fields" do
|
||||||
json = CustomWizardSerializer.new(build_wizard, scope: Guardian.new(user)).as_json
|
@template[:steps][2][:fields].delete_at(2)
|
||||||
expect(json[:custom_wizard][:categories].present?).to eq(false)
|
CustomWizard::Template.save(@template)
|
||||||
expect(json[:custom_wizard][:uncategorized_category_id].present?).to eq(false)
|
|
||||||
|
json = CustomWizard::WizardSerializer.new(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build,
|
||||||
|
scope: Guardian.new(user)
|
||||||
|
).as_json
|
||||||
|
expect(json[:wizard][:categories].present?).to eq(false)
|
||||||
|
expect(json[:wizard][:uncategorized_category_id].present?).to eq(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should return category attributes if there is a category selector field" do
|
it "should return categories if there is a category selector field" do
|
||||||
template['steps'][0]['fields'][0] = category_field
|
json = CustomWizard::WizardSerializer.new(
|
||||||
json = CustomWizardSerializer.new(build_wizard(template), scope: Guardian.new(user)).as_json
|
CustomWizard::Builder.new(@template[:id], user).build,
|
||||||
expect(json[:custom_wizard][:categories].present?).to eq(true)
|
scope: Guardian.new(user)
|
||||||
expect(json[:custom_wizard][:uncategorized_category_id].present?).to eq(true)
|
).as_json
|
||||||
|
expect(json[:wizard][:categories].present?).to eq(true)
|
||||||
|
expect(json[:wizard][:uncategorized_category_id].present?).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return groups if there is a group selector field' do
|
||||||
|
json = CustomWizard::WizardSerializer.new(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build,
|
||||||
|
scope: Guardian.new(user)
|
||||||
|
).as_json
|
||||||
|
expect(json[:wizard][:groups].length).to eq(8)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should not return groups if there is not a group selector field' do
|
||||||
|
@template[:steps][2][:fields].delete_at(3)
|
||||||
|
CustomWizard::Template.save(@template)
|
||||||
|
|
||||||
|
json = CustomWizard::WizardSerializer.new(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build,
|
||||||
|
scope: Guardian.new(user)
|
||||||
|
).as_json
|
||||||
|
expect(json[:wizard][:groups].present?).to eq(false)
|
||||||
end
|
end
|
||||||
end
|
end
|
59
spec/serializers/custom_wizard/wizard_step_serializer.rb
Normale Datei
59
spec/serializers/custom_wizard/wizard_step_serializer.rb
Normale Datei
|
@ -0,0 +1,59 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe CustomWizard::StepSerializer do
|
||||||
|
fab!(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
|
let(:required_data_json) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/step/required_data.json"
|
||||||
|
).read)
|
||||||
|
}
|
||||||
|
|
||||||
|
before do
|
||||||
|
CustomWizard::Template.save(
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
|
||||||
|
).read),
|
||||||
|
skip_jobs: true)
|
||||||
|
@wizard = CustomWizard::Builder.new("super_mega_fun_wizard", user).build
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return basic step attributes' do
|
||||||
|
json_array = ActiveModel::ArraySerializer.new(
|
||||||
|
@wizard.steps,
|
||||||
|
each_serializer: CustomWizard::StepSerializer,
|
||||||
|
scope: Guardian.new(user)
|
||||||
|
).as_json
|
||||||
|
expect(json_array[0][:wizard_step][:title]).to eq("Text")
|
||||||
|
expect(json_array[0][:wizard_step][:description]).to eq("Text inputs!")
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return fields' do
|
||||||
|
json_array = ActiveModel::ArraySerializer.new(
|
||||||
|
@wizard.steps,
|
||||||
|
each_serializer: CustomWizard::StepSerializer,
|
||||||
|
scope: Guardian.new(user)
|
||||||
|
).as_json
|
||||||
|
expect(json_array[0][:wizard_step][:fields].length).to eq(4)
|
||||||
|
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 'should return permitted attributes' do
|
||||||
|
json_array = ActiveModel::ArraySerializer.new(
|
||||||
|
@wizard.steps,
|
||||||
|
each_serializer: CustomWizard::StepSerializer,
|
||||||
|
scope: Guardian.new(user)
|
||||||
|
).as_json
|
||||||
|
expect(json_array[0][:wizard_step][:permitted]).to eq(false)
|
||||||
|
expect(json_array[0][:wizard_step][:permitted_message]).to eq("Missing required data")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Laden …
In neuem Issue referenzieren