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