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'
|
||||||
|
|
|
@ -27,6 +27,11 @@ en:
|
||||||
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."
|
||||||
wizard_redirect_exclude_paths: "Routes excluded from wizard redirects."
|
wizard_redirect_exclude_paths: "Routes excluded from wizard redirects."
|
||||||
|
|
|
@ -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,10 +25,10 @@ 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)
|
||||||
|
@ -43,10 +37,8 @@ class CustomWizard::AdminSubmissionsController < CustomWizard::AdminController
|
||||||
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
|
|
||||||
}.merge!(submission.except("redirect_to"))
|
|
||||||
end
|
end
|
||||||
end.flatten
|
end.flatten
|
||||||
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'
|
||||||
|
@ -33,39 +30,36 @@ class CustomWizard::TransferController < ::ApplicationController
|
||||||
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
|
end
|
||||||
|
|
||||||
countValid += 1
|
if success_ids.length == 0
|
||||||
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
|
|
||||||
|
|
||||||
if countValid == 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,26 +23,22 @@ 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
|
||||||
end
|
|
||||||
|
|
||||||
def save
|
|
||||||
opts = {}
|
|
||||||
opts[:create] = params[:create] if params[:create]
|
|
||||||
|
|
||||||
validator = CustomWizard::Validator.new(save_wizard_params.to_h, opts)
|
|
||||||
validation = validator.perform
|
|
||||||
|
|
||||||
if validation[:error]
|
|
||||||
render json: { error: validation[:error] }
|
|
||||||
else
|
|
||||||
if wizard_id = CustomWizard::Wizard.save(validation[:wizard])
|
|
||||||
render json: success_json.merge(wizard_id: wizard_id)
|
|
||||||
else
|
else
|
||||||
render json: failed_json
|
render json: failed_json
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def save
|
||||||
|
template = CustomWizard::Template.new(save_wizard_params.to_h)
|
||||||
|
wizard_id = template.save(create: params[:create])
|
||||||
|
|
||||||
|
if template.errors.any?
|
||||||
|
render json: failed_json.merge(errors: result.errors.full_messages)
|
||||||
|
else
|
||||||
|
render json: success_json.merge(wizard_id: wizard_id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -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])
|
|
||||||
|
|
||||||
permitted = params.permit(:wizard_id, :step_id)
|
wizard = @builder.build
|
||||||
if params[:fields]
|
step = wizard.steps.select { |s| s.id == update_params[:step_id] }.first
|
||||||
permitted[:fields] = params[:fields].select { |k, v| field_ids.include? k }
|
|
||||||
permitted.permit!
|
if !step || step.fields.blank?
|
||||||
|
raise Discourse::InvalidParameters.new(:step_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
wizard = CustomWizard::Builder.new(permitted[:wizard_id].underscore, current_user).build
|
field_ids = step.fields.map(&:id)
|
||||||
updater = wizard.create_updater(permitted[:step_id], permitted[:fields])
|
|
||||||
|
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
|
||||||
|
|
|
@ -2,6 +2,7 @@ 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)
|
||||||
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
@ -130,7 +135,13 @@ class CustomWizard::Action
|
||||||
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] ||= {}
|
||||||
|
@ -262,7 +273,7 @@ class CustomWizard::Action
|
||||||
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
|
||||||
|
@ -290,7 +301,14 @@ class CustomWizard::Action
|
||||||
}
|
}
|
||||||
).perform
|
).perform
|
||||||
|
|
||||||
groups = group_map.flatten.reduce([]) do |groups, g|
|
group_map = group_map.flatten.compact
|
||||||
|
|
||||||
|
unless group_map.present?
|
||||||
|
log_error("invalid group map")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
groups = group_map.reduce([]) do |groups, g|
|
||||||
begin
|
begin
|
||||||
groups.push(Integer(g))
|
groups.push(Integer(g))
|
||||||
rescue ArgumentError
|
rescue ArgumentError
|
||||||
|
@ -345,17 +363,33 @@ class CustomWizard::Action
|
||||||
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)
|
||||||
|
@ -401,6 +437,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.flatten
|
output.flatten
|
||||||
else output.is_a?(String)
|
else output.is_a?(String)
|
||||||
|
@ -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,12 +566,14 @@ class CustomWizard::Action
|
||||||
user: user
|
user: user
|
||||||
).perform
|
).perform
|
||||||
|
|
||||||
|
if value
|
||||||
value = value.parameterize(separator: '_') if attr === "name"
|
value = value.parameterize(separator: '_') if attr === "name"
|
||||||
value = value.to_i if attr.include?("_level")
|
value = value.to_i if attr.include?("_level")
|
||||||
|
|
||||||
params[attr.to_sym] = value
|
params[attr.to_sym] = value
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
add_custom_fields(params)
|
add_custom_fields(params)
|
||||||
end
|
end
|
||||||
|
@ -556,6 +596,7 @@ class CustomWizard::Action
|
||||||
user: user
|
user: user
|
||||||
).perform
|
).perform
|
||||||
|
|
||||||
|
if value
|
||||||
if attr === "parent_category_id" && value.is_a?(Array)
|
if attr === "parent_category_id" && value.is_a?(Array)
|
||||||
value = value[0]
|
value = value[0]
|
||||||
end
|
end
|
||||||
|
@ -579,9 +620,14 @@ class CustomWizard::Action
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if attr === 'slug'
|
||||||
|
value = value.parameterize(separator: '-')
|
||||||
|
end
|
||||||
|
|
||||||
params[attr.to_sym] = value
|
params[attr.to_sym] = value
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
add_custom_fields(params)
|
add_custom_fields(params)
|
||||||
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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -170,28 +131,30 @@ class CustomWizard::Builder
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if updater.errors.empty?
|
||||||
if route_to = data['route_to']
|
if route_to = data['route_to']
|
||||||
data.delete('route_to')
|
data.delete('route_to')
|
||||||
end
|
end
|
||||||
|
|
||||||
if @wizard.save_submissions && updater.errors.empty?
|
if @wizard.save_submissions
|
||||||
save_submissions(data, final_step)
|
save_submissions(data, final_step)
|
||||||
elsif final_step
|
|
||||||
PluginStore.remove("#{@wizard.id}_submissions", @wizard.user.id)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if final_step && @wizard.id === @wizard.user.custom_fields['redirect_to_wizard']
|
if final_step
|
||||||
|
if @wizard.id == @wizard.user.custom_fields['redirect_to_wizard']
|
||||||
@wizard.user.custom_fields.delete('redirect_to_wizard');
|
@wizard.user.custom_fields.delete('redirect_to_wizard');
|
||||||
@wizard.user.save_custom_fields(true)
|
@wizard.user.save_custom_fields(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
if updater.errors.empty?
|
|
||||||
if final_step
|
|
||||||
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']
|
||||||
|
params[:value] = prefill_field(field_template, step_template)
|
||||||
|
|
||||||
## Load previously submitted values
|
if !build_opts[:reset] && (submission = @wizard.current_submission)
|
||||||
if !build_opts[:reset] && @submissions.last && !@submissions.last.key?("submitted_at")
|
|
||||||
submission = @submissions.last
|
|
||||||
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
|
||||||
|
@ -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 reset_submissions
|
def save_permitted_params(permitted_params, params)
|
||||||
@submissions.pop(1) if @wizard.unfinished?
|
permitted_data = {}
|
||||||
PluginStore.set("#{@wizard.id}_submissions", @wizard.user.id, @submissions)
|
|
||||||
@wizard.reset
|
permitted_params.each do |pp|
|
||||||
|
pair = pp['pairs'].first
|
||||||
|
params_key = pair['key'].to_sym
|
||||||
|
submission_key = pair['value'].to_sym
|
||||||
|
permitted_data[submission_key] = params[params_key] if params[params_key]
|
||||||
|
end
|
||||||
|
|
||||||
|
if permitted_data.present?
|
||||||
|
current_data = @submissions.last || {}
|
||||||
|
save_submissions(current_data.merge(permitted_data), false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def ensure_required_data(step, step_template)
|
||||||
|
step_template['required_data'].each do |required|
|
||||||
|
pairs = required['pairs'].select do |pair|
|
||||||
|
pair['key'].present? && pair['value'].present?
|
||||||
|
end
|
||||||
|
|
||||||
|
if pairs.any? && !@submissions.last
|
||||||
|
step.permitted = false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
pairs.each do |pair|
|
||||||
|
pair['key'] = @submissions.last[pair['key']]
|
||||||
|
end
|
||||||
|
|
||||||
|
if !mapper.validate_pairs(pairs)
|
||||||
|
step.permitted = false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
step
|
||||||
end
|
end
|
||||||
end
|
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
|
|
@ -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)
|
|
||||||
|
|
||||||
after_time = nil
|
|
||||||
|
|
||||||
if !@error && @params[:after_time]
|
|
||||||
validate_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?
|
if data[:fields].present?
|
||||||
params[:fields].each do |field|
|
data[:fields].each do |field|
|
||||||
check_required(field, :field)
|
check_required(field, :field)
|
||||||
check_depdendent(field, :field)
|
|
||||||
break if @error.present?
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if params[:actions].present?
|
if data[:actions].present?
|
||||||
params[:actions].each do |action|
|
data[:actions].each do |action|
|
||||||
check_required(action, :action)
|
check_required(action, :action)
|
||||||
check_depdendent(action, :action)
|
|
||||||
break if @error.present?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
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
|
|
||||||
|
|
||||||
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
|
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,9 +56,17 @@ 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)
|
||||||
end
|
end
|
||||||
|
@ -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
|
|
||||||
")
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.after_signup(user)
|
|
||||||
if (records = filter_records('after_signup')).any?
|
|
||||||
result = false
|
|
||||||
|
|
||||||
records
|
|
||||||
.sort_by { |record| record.value['permitted'].present? ? 0 : 1 }
|
|
||||||
.each do |record|
|
|
||||||
wizard = self.new(JSON.parse(record.value), user)
|
|
||||||
|
|
||||||
if wizard.permitted?
|
|
||||||
result = wizard
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
result
|
|
||||||
else
|
else
|
||||||
false
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.prompt_completion(user)
|
def set_submissions(submissions)
|
||||||
if (records = filter_records('prompt_completion')).any?
|
PluginStore.set("#{id}_submissions", user.id, Array.wrap(submissions))
|
||||||
records.reduce([]) do |result, record|
|
|
||||||
wizard = CustomWizard::Wizard.new(::JSON.parse(record.value), user)
|
|
||||||
|
|
||||||
if wizard.permitted? && !wizard.completed?
|
|
||||||
result.push(id: wizard.id, name: wizard.name)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
result
|
def self.submissions(wizard_id, user)
|
||||||
end
|
new({ id: wizard_id }, user).submissions
|
||||||
else
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.restart_on_revisit
|
def self.set_submissions(wizard_id, user, submissions)
|
||||||
if (records = filter_records('restart_on_revisit')).any?
|
new({ id: wizard_id }, user).set_submissions(submissions)
|
||||||
records.first.key
|
|
||||||
else
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.steps(wizard_id)
|
|
||||||
wizard = PluginStore.get('custom_wizard', wizard_id)
|
|
||||||
wizard ? wizard['steps'] : nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.step_ids(wizard_id)
|
|
||||||
steps = self.steps(wizard_id)
|
|
||||||
return [] if !steps
|
|
||||||
steps.map { |s| s['id'] }.flatten.uniq
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.field_ids(wizard_id, step_id)
|
|
||||||
steps = self.steps(wizard_id)
|
|
||||||
return [] if !steps
|
|
||||||
step = steps.select { |s| s['id'] === step_id }.first
|
|
||||||
if step && fields = step['fields']
|
|
||||||
fields.map { |f| f['id'] }
|
|
||||||
else
|
|
||||||
[]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.add_wizard(obj)
|
|
||||||
wizard = obj.is_a?(String) ? ::JSON.parse(json) : obj
|
|
||||||
PluginStore.set('custom_wizard', wizard["id"], wizard)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.find(wizard_id)
|
|
||||||
PluginStore.get('custom_wizard', wizard_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.list(user=nil)
|
|
||||||
PluginStoreRow.where(plugin_name: 'custom_wizard').order(:id)
|
|
||||||
.reduce([]) do |result, record|
|
|
||||||
attrs = JSON.parse(record.value)
|
|
||||||
|
|
||||||
if attrs.present? &&
|
|
||||||
attrs.is_a?(Hash) &&
|
|
||||||
attrs['id'].present? &&
|
|
||||||
attrs['name'].present?
|
|
||||||
|
|
||||||
result.push(self.new(attrs, user))
|
|
||||||
end
|
|
||||||
|
|
||||||
result
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.save(wizard)
|
|
||||||
existing_wizard = self.create(wizard[:id])
|
|
||||||
|
|
||||||
wizard[:steps].each do |step|
|
|
||||||
if step[:raw_description]
|
|
||||||
step[:description] = PrettyText.cook(step[:raw_description])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
wizard = wizard.slice!(:create)
|
|
||||||
|
|
||||||
ActiveRecord::Base.transaction do
|
|
||||||
PluginStore.set('custom_wizard', wizard[:id], wizard)
|
|
||||||
|
|
||||||
if wizard[:after_time]
|
|
||||||
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: wizard[:id])
|
|
||||||
enqueue_at = Time.parse(wizard[:after_time_scheduled]).utc
|
|
||||||
Jobs.enqueue_at(enqueue_at, :set_after_time_wizard, wizard_id: wizard[:id])
|
|
||||||
end
|
|
||||||
|
|
||||||
if existing_wizard && existing_wizard.after_time && !wizard[:after_time]
|
|
||||||
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: wizard[:id])
|
|
||||||
Jobs.enqueue(:clear_after_time_wizard, wizard_id: wizard[:id])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
wizard[:id]
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.remove(wizard_id)
|
|
||||||
wizard = self.create(wizard_id)
|
|
||||||
|
|
||||||
ActiveRecord::Base.transaction do
|
|
||||||
if wizard.after_time
|
|
||||||
Jobs.cancel_scheduled_job(:set_after_time_wizard)
|
|
||||||
Jobs.enqueue(:clear_after_time_wizard, wizard_id: wizard.id)
|
|
||||||
end
|
|
||||||
|
|
||||||
PluginStore.remove('custom_wizard', wizard.id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.exists?(wizard_id)
|
|
||||||
PluginStoreRow.exists?(plugin_name: 'custom_wizard', key: wizard_id)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.create(wizard_id, user = nil)
|
def self.create(wizard_id, user = nil)
|
||||||
if wizard = self.find(wizard_id)
|
if template = CustomWizard::Template.find(wizard_id)
|
||||||
self.new(wizard.to_h, user)
|
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
|
||||||
|
|
||||||
|
def self.after_signup(user)
|
||||||
|
wizards = list(
|
||||||
|
user,
|
||||||
|
template_opts: {
|
||||||
|
setting: 'after_signup',
|
||||||
|
order: "(value::json ->> 'permitted') IS NOT NULL DESC"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
wizards.any? ? wizards.first : false
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.prompt_completion(user)
|
||||||
|
wizards = list(
|
||||||
|
user,
|
||||||
|
template_opts: {
|
||||||
|
setting: 'prompt_completion',
|
||||||
|
order: "(value::json ->> 'permitted') IS NOT NULL DESC"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if wizards.any?
|
||||||
|
wizards.map do |w|
|
||||||
|
{
|
||||||
|
id: w.id,
|
||||||
|
name: w.name
|
||||||
|
}
|
||||||
|
end
|
||||||
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
|
||||||
|
|
12
plugin.rb
12
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,7 +161,11 @@ after_initialize do
|
||||||
::Wizard::Field.prepend CustomWizardFieldExtension
|
::Wizard::Field.prepend CustomWizardFieldExtension
|
||||||
::Wizard::Step.prepend CustomWizardStepExtension
|
::Wizard::Step.prepend CustomWizardStepExtension
|
||||||
|
|
||||||
CustomWizard::Wizard.register_styles
|
full_path = "#{Rails.root}/plugins/discourse-custom-wizard/assets/stylesheets/wizard/wizard_custom.scss"
|
||||||
|
DiscoursePluginRegistry.register_asset(full_path, {}, "wizard_custom")
|
||||||
|
Stylesheet::Importer.register_import("wizard_custom") do
|
||||||
|
import_files(DiscoursePluginRegistry.stylesheets["wizard_custom"])
|
||||||
|
end
|
||||||
|
|
||||||
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
|
||||||
|
|
|
@ -1,19 +1,41 @@
|
||||||
|
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)
|
||||||
|
@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
|
||||||
)
|
)
|
||||||
topic = Topic.where(title: "Topic Title")
|
|
||||||
|
|
||||||
expect(topic.exists?).to eq(true)
|
expect(topic.exists?).to eq(true)
|
||||||
expect(Post.where(
|
expect(Post.where(
|
||||||
topic_id: topic.pluck(:id),
|
topic_id: topic.pluck(:id),
|
||||||
|
@ -21,72 +43,120 @@ describe CustomWizard::Action do
|
||||||
).exists?).to eq(true)
|
).exists?).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'sends a message' do
|
it "fails silently without basic topic inputs" do
|
||||||
fields = [text_field, textarea_field]
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
wizard.create_updater(
|
||||||
|
wizard.steps.first.id,
|
||||||
|
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
|
||||||
|
|
||||||
if extra_field
|
expect(updater.success?).to eq(true)
|
||||||
fields.push(extra_field)
|
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
|
||||||
|
|
||||||
template['steps'][0]['fields'] = fields
|
it 'sends a message' do
|
||||||
template['steps'][0]["actions"] = [send_message_action.merge(extra_action_opts)]
|
User.create(username: 'angus1', email: "angus1@email.com")
|
||||||
|
|
||||||
run_update(template, nil,
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
text: "Message Title",
|
wizard.create_updater(wizard.steps[0].id, {}).update
|
||||||
textarea: "message body"
|
wizard.create_updater(wizard.steps[1].id, {}).update
|
||||||
)
|
|
||||||
|
|
||||||
topic = Topic.where(
|
topic = Topic.where(
|
||||||
archetype: Archetype.private_message,
|
archetype: Archetype.private_message,
|
||||||
title: "Message Title"
|
title: "Message title"
|
||||||
|
)
|
||||||
|
|
||||||
|
post = Post.where(
|
||||||
|
topic_id: topic.pluck(:id),
|
||||||
|
raw: "I will interpolate some wizard fields"
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(topic.exists?).to eq(true)
|
expect(topic.exists?).to eq(true)
|
||||||
expect(
|
expect(topic.first.topic_allowed_users.first.user.username).to eq('angus1')
|
||||||
topic.first.topic_allowed_users.first.user.username
|
expect(post.exists?).to eq(true)
|
||||||
).to eq('angus')
|
|
||||||
expect(Post.where(
|
|
||||||
topic_id: topic.pluck(:id),
|
|
||||||
raw: "message body"
|
|
||||||
).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"
|
|
||||||
|
category = Category.find_by(id: wizard.current_submission['action_8'])
|
||||||
|
|
||||||
|
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"
|
||||||
)
|
)
|
||||||
|
end
|
||||||
|
|
||||||
expect(updater.result.blank?).to eq(true)
|
it 'creates a category' 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(Category.where(id: wizard.current_submission['action_8']).exists?).to eq(true)
|
||||||
|
end
|
||||||
|
|
||||||
updater = run_update(template, template['steps'][1]['id'])
|
it 'creates a group' do
|
||||||
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
expect(updater.result[:redirect_on_complete]).to eq(
|
step_id = wizard.steps[0].id
|
||||||
"/new-topic?title=Topic%20Title&body=topic%20body"
|
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
|
end
|
||||||
|
|
||||||
it 'adds a user to a group' do
|
it 'adds a user to a group' do
|
||||||
template['steps'][0]['fields'] = [dropdown_groups_field]
|
wizard = CustomWizard::Builder.new(@template[:id], user).build
|
||||||
template['steps'][0]["actions"] = [add_to_group_action]
|
step_id = wizard.steps[0].id
|
||||||
|
updater = wizard.create_updater(step_id, step_1_field_1: "Text input").update
|
||||||
updater = run_update(template, nil, dropdown_groups: group.id)
|
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(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/step/required_data.json"
|
||||||
|
).read)
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:permitted_json) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/permitted.json"
|
||||||
|
).read)
|
||||||
|
}
|
||||||
|
|
||||||
|
let(:permitted_param_json) {
|
||||||
|
JSON.parse(File.open(
|
||||||
|
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/step/permitted_params.json"
|
||||||
|
).read)
|
||||||
|
}
|
||||||
|
|
||||||
|
before do
|
||||||
|
Group.refresh_automatic_group!(:trust_level_3)
|
||||||
|
CustomWizard::Template.save(
|
||||||
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/wizard.json"
|
||||||
).read)
|
).read),
|
||||||
end
|
skip_jobs: true)
|
||||||
|
@template = CustomWizard::Template.find('super_mega_fun_wizard')
|
||||||
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
|
|
||||||
|
|
||||||
def add_submission_data(data = {})
|
|
||||||
PluginStore.set("welcome_submissions", user.id, {
|
|
||||||
name: 'Angus',
|
|
||||||
website: 'https://thepavilion.io'
|
|
||||||
}.merge(data))
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_submission_data
|
|
||||||
PluginStore.get("welcome_submissions", user.id)
|
|
||||||
end
|
|
||||||
|
|
||||||
def run_update(t = template, step_id = nil, data = {})
|
|
||||||
wizard = build_wizard(t)
|
|
||||||
updater = wizard.create_updater(step_id || t['steps'][0]['id'], data)
|
|
||||||
updater.update
|
|
||||||
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,123 +61,287 @@ describe CustomWizard::Builder do
|
||||||
SiteSetting.custom_wizard_enabled = true
|
SiteSetting.custom_wizard_enabled = true
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns steps" do
|
it "returns wizard metadata" do
|
||||||
expect(build_wizard.steps.length).to eq(2)
|
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
|
end
|
||||||
|
|
||||||
it 'returns no steps if multiple submissions are disabled and user has completed' do
|
it "returns steps" do
|
||||||
history_params = {
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.steps.length
|
||||||
|
).to eq(3)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with multiple submissions disabled" do
|
||||||
|
before do
|
||||||
|
@template[:multiple_submissions] = false
|
||||||
|
CustomWizard::Template.save(@template.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns steps if user has not completed it' do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.steps.length
|
||||||
|
).to eq(3)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns no steps if user has completed it' do
|
||||||
|
@template[:steps].each do |step|
|
||||||
|
UserHistory.create!(
|
||||||
|
{
|
||||||
action: UserHistory.actions[:custom_wizard_step],
|
action: UserHistory.actions[:custom_wizard_step],
|
||||||
acting_user_id: user.id,
|
acting_user_id: user.id,
|
||||||
context: template['id']
|
context: @template[:id]
|
||||||
}
|
}.merge(
|
||||||
UserHistory.create!(history_params.merge(subject: template['steps'][0]['id']))
|
subject: step[:id]
|
||||||
UserHistory.create!(history_params.merge(subject: template['steps'][1]['id']))
|
)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
template["multiple_submissions"] = false
|
expect(
|
||||||
expect(build_wizard(template).steps.length).to eq(0)
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.steps.length
|
||||||
|
).to eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with restricted permissions" do
|
||||||
|
before do
|
||||||
|
@template[:permitted] = permitted_json["permitted"]
|
||||||
|
CustomWizard::Template.save(@template.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'is not permitted if user is not in permitted group' do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.permitted?
|
||||||
|
).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'user cannot access if not permitted' do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.can_access?
|
||||||
|
).to eq(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns wizard metadata if user is not permitted' do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.name
|
||||||
|
).to eq("Super Mega Fun Wizard")
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns no steps if user is not permitted' do
|
it 'returns no steps if user is not permitted' do
|
||||||
template["min_trust"] = 3
|
expect(
|
||||||
expect(build_wizard(template).steps.length).to eq(0)
|
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
|
end
|
||||||
|
|
||||||
it 'returns steps if user is permitted' do
|
it 'returns steps if user is permitted' do
|
||||||
template["min_trust"] = 3
|
expect(
|
||||||
expect(build_wizard(template, trusted_user).steps.length).to eq(2)
|
CustomWizard::Builder.new(@template[:id], trusted_user).build
|
||||||
|
.steps.length
|
||||||
|
).to eq(3)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns a wizard with prefilled data if user has partially completed it' do
|
it 'returns prefilled data' do
|
||||||
add_submission_data
|
expect(
|
||||||
wizard = build_wizard
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
expect(wizard.steps[0].fields.first.value).to eq('Angus')
|
.steps.first
|
||||||
expect(wizard.steps[1].fields.first.value).to eq('https://thepavilion.io')
|
.fields.first
|
||||||
|
.value
|
||||||
|
).to eq('I am prefilled')
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns a wizard with no prefilled data if options include reset' do
|
context "user has partially completed" do
|
||||||
add_submission_data
|
before do
|
||||||
wizard = build_wizard(template, user, reset: true)
|
wizard = CustomWizard::Wizard.new(@template, user)
|
||||||
expect(wizard.steps[0].fields.first.value).to eq(nil)
|
wizard.set_submissions(step_1_field_1: 'I am a user submission')
|
||||||
expect(wizard.steps[1].fields.first.value).to eq(nil)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'building steps' do
|
it 'returns saved submissions' do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.steps.first
|
||||||
|
.fields.first
|
||||||
|
.value
|
||||||
|
).to eq('I am a user submission')
|
||||||
|
end
|
||||||
|
|
||||||
|
context "restart is enabled" do
|
||||||
|
before do
|
||||||
|
@template[:restart_on_revisit] = true
|
||||||
|
CustomWizard::Template.save(@template.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not return saved submissions' do
|
||||||
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.steps.first
|
||||||
|
.fields.first
|
||||||
|
.value
|
||||||
|
).to eq('I am prefilled')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'building step' do
|
||||||
it 'returns step metadata' do
|
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
|
end
|
||||||
|
|
||||||
it 'is not permitted if required data is not present' do
|
it 'is not permitted if required data is not present' do
|
||||||
template['steps'][0]['required_data'] = required_data
|
expect(
|
||||||
expect(build_wizard(template, user).steps[0].permitted).to eq(false)
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.steps.first
|
||||||
|
.permitted
|
||||||
|
).to eq(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'it shows required data message if required data has message' do
|
it 'it shows required data message' do
|
||||||
template['steps'][0]['required_data'] = required_data
|
expect(
|
||||||
template['steps'][0]['required_data_message'] = required_data_message
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
add_submission_data(nickname: "John")
|
.steps.first
|
||||||
wizard = build_wizard(template, user)
|
.permitted_message
|
||||||
expect(wizard.steps[0].permitted).to eq(false)
|
).to eq("Missing required data")
|
||||||
expect(wizard.steps[0].permitted_message).to eq(required_data_message)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'is permitted if required data is present' do
|
it 'is permitted if required data is present' do
|
||||||
template['steps'][0]['required_data'] = required_data
|
CustomWizard::Wizard.set_submissions('super_mega_fun_wizard', user,
|
||||||
PluginStore.set('welcome_submissions', user.id, nickname: "Angus", name: "Angus")
|
required_data: "required_value"
|
||||||
expect(build_wizard(template, user).steps[0].permitted).to eq(true)
|
)
|
||||||
|
expect(
|
||||||
|
CustomWizard::Builder.new(@template[:id], user).build
|
||||||
|
.steps.first
|
||||||
|
.permitted
|
||||||
|
).to eq(true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "with permitted params" do
|
||||||
|
before do
|
||||||
|
@template[:steps][0][:permitted_params] = permitted_param_json['permitted_params']
|
||||||
|
CustomWizard::Template.save(@template.as_json)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'saves permitted params' do
|
||||||
|
wizard = CustomWizard::Builder.new(@template[:id], user).build({},
|
||||||
|
param: 'param_value'
|
||||||
|
)
|
||||||
|
expect(wizard.current_submission['saved_param']).to eq('param_value')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'building field' do
|
||||||
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')
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'runs actions attached to a step' do
|
expect(
|
||||||
run_update(template, template['steps'][1]['id'], name: "Gus")
|
perform_update('step_1', step_1_field_2: nil)
|
||||||
expect(user.name).to eq('Gus')
|
.errors.messages[:step_1_field_2].first
|
||||||
|
).to eq(I18n.t('wizard.field.required', label: 'Textarea'))
|
||||||
|
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": []
|
||||||
|
}
|
511
spec/fixtures/wizard.json
gevendort
511
spec/fixtures/wizard.json
gevendort
|
@ -1,50 +1,517 @@
|
||||||
{
|
{
|
||||||
"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": "about_you",
|
"id": "step_1_field_2",
|
||||||
"title": "Tell us about you",
|
"label": "Textarea",
|
||||||
"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": "textarea",
|
||||||
"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>",
|
"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": [
|
"fields": [
|
||||||
{
|
{
|
||||||
"id": "website",
|
"id": "step_2_field_1",
|
||||||
"label": "Website",
|
"label": "Date",
|
||||||
"type": "text"
|
"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": [
|
"actions": [
|
||||||
{
|
{
|
||||||
"id": "update_profile",
|
"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": "action_6",
|
||||||
|
"run_after": "step_1",
|
||||||
|
"type": "add_to_group",
|
||||||
|
"group": [
|
||||||
|
{
|
||||||
|
"type": "assignment",
|
||||||
|
"output": "action_9",
|
||||||
|
"output_type": "wizard_action",
|
||||||
|
"output_connector": "set"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "action_8",
|
||||||
|
"run_after": "step_1",
|
||||||
|
"type": "create_category",
|
||||||
|
"custom_fields": [
|
||||||
|
{
|
||||||
|
"type": "association",
|
||||||
|
"pairs": [
|
||||||
|
{
|
||||||
|
"index": 0,
|
||||||
|
"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",
|
"type": "update_profile",
|
||||||
"profile_updates": [
|
"profile_updates": [
|
||||||
{
|
{
|
||||||
"key": "name",
|
"type": "association",
|
||||||
"value": "name"
|
"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
|
||||||
|
SiteSetting.custom_wizard_enabled = false
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns a missing message if no wizard exists' do
|
it 'redirects to root' do
|
||||||
|
get '/w/super-mega-fun-wizard', xhr: true
|
||||||
|
expect(response).to redirect_to("/")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns a custom wizard theme' do
|
it 'returns wizard' do
|
||||||
|
get '/w/super-mega-fun-wizard.json'
|
||||||
|
expect(response.parsed_body["id"]).to eq("super_mega_fun_wizard")
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'updates the page title' do
|
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
|
end
|
||||||
|
|
||||||
it 'skips a wizard if user is allowed to skip' do
|
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
|
||||||
|
CustomWizard::Template.save(
|
||||||
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/wizard.json"
|
||||||
).read)
|
).read),
|
||||||
end
|
skip_jobs: true)
|
||||||
|
@template = CustomWizard::Template.find('super_mega_fun_wizard')
|
||||||
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
|
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