0
0
Fork 1
Spiegel von https://github.com/paviliondev/discourse-custom-wizard.git synchronisiert 2024-11-22 09:20:29 +01:00
Dieser Commit ist enthalten in:
Angus McLeod 2020-11-03 11:24:20 +11:00
Ursprung b726d40a0c
Commit fc7c5b9b34
60 geänderte Dateien mit 2138 neuen und 479 gelöschten Zeilen

Datei anzeigen

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

Datei anzeigen

@ -33,8 +33,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

Datei anzeigen

@ -9,5 +9,6 @@ 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
end

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -4,7 +4,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
def index
render_json_dump(
wizard_list: ActiveModel::ArraySerializer.new(
CustomWizard::Template.list,
CustomWizard::Wizard.list(current_user),
each_serializer: CustomWizard::BasicWizardSerializer
),
field_types: CustomWizard::Field.types
@ -30,20 +30,13 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
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::Template.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

Datei anzeigen

@ -15,22 +15,24 @@ class CustomWizard::StepsController < ::ApplicationController
field_ids = step.fields.map(&:id)
update = update_params.to_h
if params[:fields]
permitted_fields = params[:fields].select { |k, v| field_ids.include? k }
update_params[:fields] = permitted_fields
update_params.permit!
update[:fields] = {}
params[:fields].each do |k, v|
update[:fields][k] = v if field_ids.include? k
end
end
updater = wizard.create_updater(
update_params[:step_id],
update_params[:fields]
)
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 = []

Datei anzeigen

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

Datei anzeigen

@ -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 = []

Datei anzeigen

@ -267,7 +267,7 @@ class CustomWizard::Action
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
@ -412,6 +412,8 @@ class CustomWizard::Action
data: data,
user: user
).perform
return false unless output.present?
if output.is_a?(Array)
output.first
@ -428,6 +430,8 @@ class CustomWizard::Action
data: data,
user: user,
).perform
return false unless output.present?
if output.is_a?(Array)
output.flatten
@ -483,11 +487,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

Datei anzeigen

@ -49,7 +49,6 @@ class CustomWizard::Builder
return @wizard if !@wizard.can_access?
build_opts[:reset] = build_opts[:reset] || @wizard.restart_on_revisit
reset_submissions if build_opts[:reset]
@steps.each do |step_template|
@wizard.append_step(step_template['id']) do |step|
@ -110,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
@ -133,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
@ -177,10 +176,8 @@ class CustomWizard::Builder
params[:key] = field_template['key'] if field_template['key']
params[:min_length] = field_template['min_length'] if field_template['min_length']
params[:value] = prefill_field(field_template, step_template)
## Load previously submitted values
if !build_opts[:reset] && @submissions.last && !@submissions.last.key?("submitted_at")
submission = @submissions.last
if !build_opts[:reset] && (submission = @wizard.current_submission)
params[:value] = submission[field_template['id']] if submission[field_template['id']]
end
@ -359,15 +356,9 @@ 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 reset_submissions
@submissions.pop(1) if @wizard.unfinished?
PluginStore.set("#{@wizard.id}_submissions", @wizard.user.id, @submissions)
@wizard.reset
end
def save_permitted_params(permitted_params, params)
permitted_data = {}

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -144,7 +144,7 @@ class CustomWizard::Mapper
end
if operator == '=~'
result == 0 ? true : false
result.nil? ? false : true
else
result
end

Datei anzeigen

@ -1,53 +1,48 @@
class CustomWizard::Template
def self.add(obj)
wizard = obj.is_a?(String) ? ::JSON.parse(json) : obj
PluginStore.set('custom_wizard', wizard["id"], wizard)
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.save(data)
data = data.with_indifferent_access
existing = self.find(data[:id])
data[:steps].each do |step|
if step[:raw_description]
step[:description] = PrettyText.cook(step[:raw_description])
end
end
data = data.slice!(:create)
ActiveRecord::Base.transaction do
PluginStore.set('custom_wizard', data[:id], data)
if data[:after_time]
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: data[:id])
enqueue_at = Time.parse(data[:after_time_scheduled]).utc
Jobs.enqueue_at(enqueue_at, :set_after_time_wizard, wizard_id: data[:id])
end
if existing && existing[:after_time] && !data[:after_time]
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: data[:id])
Jobs.enqueue(:clear_after_time_wizard, wizard_id: data[:id])
end
end
data[:id]
end
def self.remove(wizard_id)
wizard = self.create(wizard_id)
wizard = CustomWizard::Wizard.create(wizard_id)
ActiveRecord::Base.transaction do
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)
Jobs.enqueue(:clear_after_time_wizard, wizard_id: wizard_id)
end
PluginStore.remove('custom_wizard', wizard.id)
end
end
@ -55,8 +50,11 @@ class CustomWizard::Template
PluginStoreRow.exists?(plugin_name: 'custom_wizard', key: wizard_id)
end
def self.list(user=nil)
PluginStoreRow.where(plugin_name: 'custom_wizard').order(:id)
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)
@ -72,10 +70,46 @@ class CustomWizard::Template
end
end
def self.setting_enabled(attr)
PluginStoreRow.where("
plugin_name = 'custom_wizard' AND
(value::json ->> '#{attr}')::boolean IS TRUE
")
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

Datei anzeigen

@ -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::Template.exists?(object[:id])
@error = {
type: 'conflict',
params: { type: type, property: 'id', value: 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

Datei anzeigen

@ -26,22 +26,24 @@ class CustomWizard::Wizard
: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,10 +55,17 @@ class CustomWizard::Wizard
end
@first_step = nil
@step_ids = attrs['steps'].map { |s| s['id'] }
@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)
@ -69,9 +78,9 @@ class CustomWizard::Wizard
last_step = steps.last
steps << step
if steps.size == 1
first_step = step
@first_step = step
step.index = 0
elsif last_step.present?
last_step.next = step
@ -94,14 +103,14 @@ class CustomWizard::Wizard
last_index = steps.index { |s| s.id == step_id }
steps[last_index + 1]
else
first_step
@first_step
end
end
def create_updater(step_id, fields)
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?
@ -116,7 +125,7 @@ class CustomWizard::Wizard
if most_recent && most_recent.subject == "reset"
false
elsif most_recent
most_recent.subject != steps.last.id
most_recent.subject != steps.last.id
else
true
end
@ -134,7 +143,7 @@ class CustomWizard::Wizard
if after_time
history = history.where("updated_at > ?", after_time_scheduled)
end
completed = history.distinct.order(:subject).pluck(:subject)
(step_ids - completed).empty?
end
@ -166,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
@ -191,63 +201,76 @@ class CustomWizard::Wizard
Array.wrap(PluginStore.get("#{id}_submissions", user.id))
end
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)
self.new(template.to_h, user)
new(template.to_h, user)
else
false
end
end
def self.list(user=nil)
CustomWizard::Template.list.map { |template| self.new(template.to_h, user) }
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 = CustomWizard::Template.setting_enabled('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 = CustomWizard::Template.setting_enabled('prompt_completion')).any?
records.reduce([]) do |result, record|
wizard = self.new(::JSON.parse(record.value), user)
if wizard.permitted? && !wizard.completed?
result.push(id: wizard.id, name: wizard.name)
end
result
wizards = list(
user,
template_opts: {
setting: 'prompt_completion',
order: "(value::json ->> 'permitted') IS NOT NULL DESC"
}
)
if wizards.any?
wizards.map do |w|
{
id: w.id,
name: w.name
}
end
else
false
end
end
def self.restart_on_revisit
if (records = CustomWizard::Template.setting_enabled('restart_on_revisit')).any?
records.first.key
else
false
end
end
def self.set_submission_redirect(user, wizard_id, url)
PluginStore.set("#{wizard_id.underscore}_submissions", user.id, [{ redirect_to: url }])
end

Datei anzeigen

@ -42,9 +42,9 @@ 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/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
@ -128,8 +128,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

Datei anzeigen

@ -7,31 +7,62 @@ describe CustomWizard::Action do
before do
Group.refresh_automatic_group!(:trust_level_2)
CustomWizard::Template.add(
CustomWizard::Template.save(
JSON.parse(File.open(
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
).read)
)
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
).read),
skip_jobs: true)
@template = CustomWizard::Template.find('super_mega_fun_wizard')
end
it 'creates a topic' do
wizard = CustomWizard::Builder.new(@template[:id], user).build
updater = wizard.create_updater(
wizard.steps[0].id,
step_1_field_1: "Topic Title",
step_1_field_2: "topic body"
).update
updater2 = wizard.create_updater(wizard.steps[1].id, {}).update
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
topic = Topic.where(title: "Topic Title")
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
@ -79,8 +110,7 @@ describe CustomWizard::Action do
updater = wizard.create_updater(wizard.steps[1].id, {})
updater.update
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
category = Category.find_by(id: submissions.first['action_8'])
category = Category.find_by(id: wizard.current_submission['action_8'])
expect(updater.result[:redirect_on_next]).to eq(
"/new-topic?title=Title%20of%20the%20composer%20topic&body=I%20am%20interpolating%20some%20user%20fields%20Angus%20angus%20angus@email.com&category=#{category.slug}/#{category.id}&tags=tag1"
@ -91,24 +121,21 @@ describe CustomWizard::Action 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
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
expect(Category.where(id: submissions.first['action_8']).exists?).to eq(true)
expect(Category.where(id: 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
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
expect(Group.where(name: submissions.first['action_9']).exists?).to eq(true)
expect(Group.where(name: 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
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
group = Group.find_by(name: submissions.first['action_9'])
group = Group.find_by(name: wizard.current_submission['action_9'])
expect(group.users.first.username).to eq('angus')
end
@ -116,9 +143,8 @@ describe CustomWizard::Action 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
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
expect(CategoryUser.where(
category_id: submissions.first['action_8'],
category_id: wizard.current_submission['action_8'],
user_id: user.id
).first.notification_level).to eq(2)
expect(CategoryUser.where(

Datei anzeigen

@ -18,7 +18,7 @@ describe CustomWizard::Builder do
let(:required_data_json) {
JSON.parse(File.open(
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/required_data.json"
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/step/required_data.json"
).read)
}
@ -36,11 +36,11 @@ describe CustomWizard::Builder do
before do
Group.refresh_automatic_group!(:trust_level_3)
CustomWizard::Template.add(
CustomWizard::Template.save(
JSON.parse(File.open(
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
).read)
)
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
).read),
skip_jobs: true)
@template = CustomWizard::Template.find('super_mega_fun_wizard')
end
@ -175,9 +175,8 @@ describe CustomWizard::Builder do
context "user has partially completed" do
before do
PluginStore.set("super_mega_fun_wizard_submissions", user.id,
step_1_field_1: 'I am a user submission'
)
wizard = CustomWizard::Wizard.new(@template, user)
wizard.set_submissions(step_1_field_1: 'I am a user submission')
end
it 'returns saved submissions' do
@ -241,7 +240,7 @@ describe CustomWizard::Builder do
end
it 'is permitted if required data is present' do
PluginStore.set('super_mega_fun_wizard_submissions', user.id,
CustomWizard::Wizard.set_submissions('super_mega_fun_wizard', user,
required_data: "required_value"
)
expect(
@ -259,13 +258,10 @@ describe CustomWizard::Builder do
end
it 'saves permitted params' do
CustomWizard::Builder.new(@template[:id], user).build({},
wizard = CustomWizard::Builder.new(@template[:id], user).build({},
param: 'param_value'
)
expect(
PluginStore.get("super_mega_fun_wizard_submissions", user.id)
.first['saved_param']
).to eq('param_value')
expect(wizard.current_submission['saved_param']).to eq('param_value')
end
end
end
@ -302,7 +298,7 @@ describe CustomWizard::Builder do
it 'saves submissions' do
perform_update('step_1', step_1_field_1: 'Text input')
expect(
PluginStore.get("super_mega_fun_wizard_submissions", user.id)
CustomWizard::Wizard.submissions(@template[:id], user)
.first['step_1_field_1']
).to eq('Text input')
end
@ -316,7 +312,7 @@ describe CustomWizard::Builder do
it "does not save submissions" do
perform_update('step_1', step_1_field_1: 'Text input')
expect(
PluginStore.get("super_mega_fun_wizard_submissions", user.id)
CustomWizard::Wizard.submissions(@template[:id], user).first
).to eq(nil)
end
end
@ -332,7 +328,7 @@ describe CustomWizard::Builder do
it 'standardises boolean entries' do
perform_update('step_2', step_2_field_5: 'false')
expect(
PluginStore.get("super_mega_fun_wizard_submissions", user.id)
CustomWizard::Wizard.submissions(@template[:id], user)
.first['step_2_field_5']
).to eq(false)
end

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -0,0 +1,250 @@
require 'rails_helper'
describe CustomWizard::Mapper do
fab!(:user1) {
Fabricate(:user,
name: "Angus",
username: "angus",
email: "angus@email.com",
trust_level: TrustLevel[3]
)
}
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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

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

@ -0,0 +1,4 @@
{
"input_1": "value 1",
"input_2": "value 2"
}

264
spec/fixtures/mapper/inputs.json gevendort Normale Datei
Datei anzeigen

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

10
spec/fixtures/step/step.json gevendort Normale Datei
Datei anzeigen

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

Datei anzeigen

@ -16,6 +16,7 @@
{
"id": "step_1_field_1",
"label": "Text",
"description": "Text field description.",
"type": "text",
"min_length": "3",
"prefill": [
@ -351,7 +352,7 @@
},
{
"id": "action_1",
"run_after": "step_2",
"run_after": "step_3",
"type": "create_topic",
"skip_redirect": true,
"post": "step_1_field_2",

4
spec/fixtures/wizard/after_time.json gevendort Normale Datei
Datei anzeigen

@ -0,0 +1,4 @@
{
"after_time": true,
"after_time_scheduled": "2020-11-20T00:59:00.000Z"
}

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -0,0 +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

Datei anzeigen

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

Datei anzeigen

@ -0,0 +1,63 @@
require 'rails_helper'
describe CustomWizard::WizardController 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
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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -0,0 +1,86 @@
# frozen_string_literal: true
require 'rails_helper'
describe CustomWizard::WizardSerializer do
fab!(:user) { Fabricate(:user) }
fab!(:category) { Fabricate(:category) }
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
it 'should return the wizard attributes' do
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 = 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 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 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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -1,13 +0,0 @@
describe CustomWizard::Mapper do
fab!(:user) { Fabricate(:user, name: 'Angus', username: 'angus', email: "angus@email.com") }
it 'interpolates user data' do
expect(
CustomWizard::Mapper.fill_placeholders(
"My name is u{name}",
user,
{}
)
).to eq('My name is Angus')
end
end

Datei anzeigen

@ -1,5 +0,0 @@
require 'rails_helper'
describe CustomWizard::AdminController do
end

Datei anzeigen

@ -1,5 +0,0 @@
require 'rails_helper'
describe ApplicationController do
end

Datei anzeigen

@ -1,31 +0,0 @@
require 'rails_helper'
describe CustomWizard::WizardController do
it 'returns a wizard if enabled' do
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
end
it 'returns a no skip message if user is not allowed to skip' do
end
end

Datei anzeigen

@ -1,45 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
describe CustomWizard::WizardSerializer do
fab!(:user) { Fabricate(:user) }
fab!(:category) { Fabricate(:category) }
before do
template = JSON.parse(File.open(
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
).read)
CustomWizard::Template.add(template)
@wizard = CustomWizard::Wizard.create('super_mega_fun_wizard', user)
end
it 'should return the wizard attributes' do
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
json = CustomWizard::WizardSerializer.new(built_wizard, scope: Guardian.new(user)).as_json
expect(json[:custom_wizard][:id]).to eq("super_mega_fun_wizard")
expect(json[:custom_wizard][:name]).to eq("Super Mega Fun Wizard")
expect(json[:custom_wizard][:background]).to eq("#333333")
expect(json[:custom_wizard][:required]).to eq(false)
end
it "should return the wizard user attributes" do
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
json = CustomWizard::WizardSerializer.new(built_wizard, scope: Guardian.new(user)).as_json
expect(json[:custom_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
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
json = CustomWizard::WizardSerializer.new(built_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)
end
it "should return category attributes if there is a category selector field" do
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
json = CustomWizard::WizardSerializer.new(built_wizard, 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)
end
end