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-10-20 10:15:03 +11:00
Ursprung 94c56ef550
Commit 8fdd263d8e
16 geänderte Dateien mit 859 neuen und 286 gelöschten Zeilen

Datei anzeigen

@ -113,6 +113,7 @@
wizardFieldSelection=true wizardFieldSelection=true
userFieldSelection='key,value' userFieldSelection='key,value'
categorySelection='output' categorySelection='output'
wizardActionSelection='output'
outputDefaultSelection='category' outputDefaultSelection='category'
context='action' context='action'
)}} )}}
@ -198,6 +199,7 @@
textSelection='value' textSelection='value'
userFieldSelection='key' userFieldSelection='key'
wizardFieldSelection='value' wizardFieldSelection='value'
wizardActionSelection='value'
keyDefaultSelection='userField' keyDefaultSelection='userField'
context='action' context='action'
)}} )}}
@ -270,6 +272,7 @@
textSelection='value,output' textSelection='value,output'
wizardFieldSelection='key,value,assignment' wizardFieldSelection='key,value,assignment'
userFieldSelection='key,value,assignment' userFieldSelection='key,value,assignment'
wizardActionSelection=true
groupSelection='value,output' groupSelection='value,output'
outputDefaultSelection='group' outputDefaultSelection='group'
context='action' context='action'

Datei anzeigen

@ -11,11 +11,11 @@ class CustomWizard::StepsController < ::ApplicationController
permitted[:fields] = params[:fields].select { |k, v| field_ids.include? k } permitted[:fields] = params[:fields].select { |k, v| field_ids.include? k }
permitted.permit! permitted.permit!
end end
wizard = CustomWizard::Builder.new(permitted[:wizard_id].underscore, current_user).build wizard = CustomWizard::Builder.new(permitted[:wizard_id].underscore, current_user).build
updater = wizard.create_updater(permitted[:step_id], permitted[:fields]) updater = wizard.create_updater(permitted[:step_id], permitted[:fields])
updater.update updater.update
if updater.success? if updater.success?
result = success_json result = success_json
result.merge!(updater.result) if updater.result result.merge!(updater.result) if updater.result

Datei anzeigen

@ -77,6 +77,11 @@ class CustomWizard::Action
multiple: true multiple: true
).perform ).perform
if targets.blank?
log_error("no recipients", "send_message has no recipients")
return
end
targets.each do |target| targets.each do |target|
if Group.find_by(name: target) if Group.find_by(name: target)
params[:target_group_names] = target params[:target_group_names] = target
@ -119,12 +124,18 @@ class CustomWizard::Action
def update_profile def update_profile
params = {} params = {}
if (profile_updates = action['profile_updates']) if (profile_updates = action['profile_updates'])
profile_updates.first[:pairs].each do |pair| profile_updates.first[:pairs].each do |pair|
if allowed_profile_field?(pair['key']) if allowed_profile_field?(pair['key'])
key = cast_profile_key(pair['key']) key = cast_profile_key(pair['key'])
value = cast_profile_value(mapper.map_field(pair['value'], pair['value_type']), pair['key']) value = cast_profile_value(
mapper.map_field(
pair['value'],
pair['value_type']
),
pair['key']
)
if user_field?(pair['key']) if user_field?(pair['key'])
params[:custom_fields] ||= {} params[:custom_fields] ||= {}
@ -137,10 +148,10 @@ class CustomWizard::Action
end end
params = add_custom_fields(params) params = add_custom_fields(params)
if params.present? if params.present?
result = UserUpdater.new(Discourse.system_user, user).update(params) result = UserUpdater.new(Discourse.system_user, user).update(params)
if params[:avatar].present? if params[:avatar].present?
result = update_avatar(params[:avatar]) result = update_avatar(params[:avatar])
end end
@ -250,11 +261,11 @@ class CustomWizard::Action
def open_composer def open_composer
params = basic_topic_params params = basic_topic_params
if params[:title].present? && params[:raw].present? if params[:title].present? && params[:raw].present?
url = "/new-topic?title=#{params[:title]}" url = "/new-topic?title=#{params[:title]}"
url += "&body=#{params[:raw]}" url += "&body=#{params[:raw]}"
if category_id = action_category if category_id = action_category
if category_id && category = Category.find(category_id) if category_id && category = Category.find(category_id)
url += "&category=#{category.full_slug('/')}" url += "&category=#{category.full_slug('/')}"
@ -266,7 +277,7 @@ class CustomWizard::Action
end end
route_to = Discourse.base_uri + URI.encode(url) route_to = Discourse.base_uri + URI.encode(url)
data['redirect_on_complete'] = route_to data['route_to'] = route_to
log_info("route: #{route_to}") log_info("route: #{route_to}")
else else
@ -283,8 +294,15 @@ class CustomWizard::Action
multiple: true multiple: true
} }
).perform ).perform
group_map = group_map.flatten.compact
unless group_map.present?
log_error("invalid group map")
return
end
groups = group_map.flatten.reduce([]) do |groups, g| groups = group_map.reduce([]) do |groups, g|
begin begin
groups.push(Integer(g)) groups.push(Integer(g))
rescue ArgumentError rescue ArgumentError
@ -324,7 +342,7 @@ class CustomWizard::Action
user: user user: user
).perform ).perform
end end
if action['code'] if action['code']
data[action['code']] = SecureRandom.hex(8) data[action['code']] = SecureRandom.hex(8)
url += "&#{action['code']}=#{data[action['code']]}" url += "&#{action['code']}=#{data[action['code']]}"
@ -336,20 +354,36 @@ class CustomWizard::Action
log_info("route: #{route_to}") log_info("route: #{route_to}")
end end
def create_group def create_group
group = group =
begin begin
Group.new(new_group_params) Group.new(new_group_params.except(:usernames, :owner_usernames))
rescue ArgumentError => e rescue ArgumentError => e
raise Discourse::InvalidParameters, "Invalid group params" raise Discourse::InvalidParameters, "Invalid group params"
end end
if group.save if group.save
GroupActionLogger.new(user, group).log_change_group_settings def get_user_ids(username_string)
User.where(username: username_string.split(",")).pluck(:id)
end
if new_group_params[:owner_usernames].present?
owner_ids = get_user_ids(new_group_params[:owner_usernames])
owner_ids.each { |user_id| group.group_users.build(user_id: user_id, owner: true) }
end
if new_group_params[:usernames].present?
user_ids = get_user_ids(new_group_params[:usernames])
user_ids -= owner_ids if owner_ids
user_ids.each { |user_id| group.group_users.build(user_id: user_id) }
end
GroupActionLogger.new(user, group, skip_guardian: true).log_change_group_settings
log_success("Group created", group.name) log_success("Group created", group.name)
result.output = group.name result.output = group.name
else else
log_error("Group creation failed") log_error("Group creation failed", group.errors.messages)
end end
end end
@ -366,7 +400,7 @@ class CustomWizard::Action
log_success("Category created", category.name) log_success("Category created", category.name)
result.output = category.id result.output = category.id
else else
log_error("Category creation failed") log_error("Category creation failed", category.errors.messages)
end end
end end
@ -378,7 +412,7 @@ class CustomWizard::Action
data: data, data: data,
user: user user: user
).perform ).perform
if output.is_a?(Array) if output.is_a?(Array)
output.first output.first
elsif output.is_a?(Integer) elsif output.is_a?(Integer)
@ -505,10 +539,12 @@ class CustomWizard::Action
user: user user: user
).perform ).perform
value = value.parameterize(separator: '_') if attr === "name" if value
value = value.to_i if attr.include?("_level") value = value.parameterize(separator: '_') if attr === "name"
value = value.to_i if attr.include?("_level")
params[attr.to_sym] = value
params[attr.to_sym] = value
end
end end
end end
@ -533,30 +569,36 @@ class CustomWizard::Action
user: user user: user
).perform ).perform
if attr === "parent_category_id" && value.is_a?(Array) if value
value = value[0] if attr === "parent_category_id" && value.is_a?(Array)
end value = value[0]
if attr === "permissions" && value.is_a?(Array)
permissions = value
value = {}
permissions.each do |p|
k = p[:key]
v = p[:value].to_i
if k.is_a?(Array)
group = Group.find_by(id: k[0])
k = group.name
else
k = k.parameterize(separator: '_')
end
value[k] = v
end end
if attr === "permissions" && value.is_a?(Array)
permissions = value
value = {}
permissions.each do |p|
k = p[:key]
v = p[:value].to_i
if k.is_a?(Array)
group = Group.find_by(id: k[0])
k = group.name
else
k = k.parameterize(separator: '_')
end
value[k] = v
end
end
if attr === 'slug'
value = value.parameterize(separator: '-')
end
params[attr.to_sym] = value
end end
params[attr.to_sym] = value
end end
end end
@ -584,6 +626,8 @@ class CustomWizard::Action
end end
def cast_profile_value(value, key) def cast_profile_value(value, key)
return value if value.nil?
if profile_url_fields.include?(key) if profile_url_fields.include?(key)
value['url'] value['url']
elsif key === 'avatar' elsif key === 'avatar'

Datei anzeigen

@ -133,7 +133,7 @@ class CustomWizard::Builder
validate_field(field, updater, step_template) if field['type'] != 'text_only' validate_field(field, updater, step_template) if field['type'] != 'text_only'
end end
end end
next if updater.errors.any? next if updater.errors.any?
CustomWizard::Builder.step_handlers.each do |handler| CustomWizard::Builder.step_handlers.each do |handler|
@ -156,10 +156,10 @@ class CustomWizard::Builder
if @actions.present? if @actions.present?
@actions.each do |action| @actions.each do |action|
if (action['run_after'] === updater.step.id) || if (action['run_after'] === updater.step.id) ||
(final_step && (!action['run_after'] || (action['run_after'] === 'wizard_completion'))) (final_step && (!action['run_after'] || (action['run_after'] === 'wizard_completion')))
CustomWizard::Action.new( CustomWizard::Action.new(
wizard: @wizard, wizard: @wizard,
action: action, action: action,
@ -217,7 +217,7 @@ class CustomWizard::Builder
submission = @submissions.last submission = @submissions.last
params[:value] = submission[field_template['id']] if submission[field_template['id']] params[:value] = submission[field_template['id']] if submission[field_template['id']]
end end
params[:value] = prefill_field(field_template, step_template) || params[:value] params[:value] = prefill_field(field_template, step_template) || params[:value]
if field_template['type'] === 'group' && params[:value].present? if field_template['type'] === 'group' && params[:value].present?
@ -339,7 +339,7 @@ class CustomWizard::Builder
if type === 'time' && value.present? && !validate_time(value) if type === 'time' && value.present? && !validate_time(value)
updater.errors.add(id, I18n.t('wizard.field.invalid_time')) updater.errors.add(id, I18n.t('wizard.field.invalid_time'))
end end
CustomWizard::Builder.field_validators.each do |validator| CustomWizard::Builder.field_validators.each do |validator|
if type === validator[:type] if type === validator[:type]
validator[:block].call(field, updater, step_template) validator[:block].call(field, updater, step_template)

Datei anzeigen

@ -48,7 +48,7 @@ class CustomWizard::Mapper
inputs.each do |input| inputs.each do |input|
input_type = input['type'] input_type = input['type']
pairs = input['pairs'] pairs = input['pairs']
if (input_type === 'conditional' && validate_pairs(pairs)) || input_type === 'assignment' if (input_type === 'conditional' && validate_pairs(pairs)) || input_type === 'assignment'
output = input['output'] output = input['output']
output_type = input['output_type'] output_type = input['output_type']

Datei anzeigen

@ -1,17 +1,27 @@
require 'rails_helper'
describe CustomWizard::Action do describe CustomWizard::Action do
let(:create_topic_action) {{"id":"create_topic","type":"create_topic","title":"text","post":"textarea"}} fab!(:user) { Fabricate(:user, name: "Angus", username: 'angus', email: "angus@email.com", trust_level: TrustLevel[2]) }
let(:send_message_action) {{"id":"send_message","type":"send_message","title":"text","post":"textarea","username":"angus"}} fab!(:category) { Fabricate(:category, name: 'cat1', slug: 'cat-slug') }
let(:route_to_action) {{"id":"route_to","type":"route_to","url":"https://google.com"}} fab!(:group) { Fabricate(:group) }
let(:open_composer_action) {{"id":"open_composer","type":"open_composer","title":"text","post":"textarea"}}
let(:add_to_group_action) {{"id":"add_to_group","type":"add_to_group","group_id":"dropdown_groups"}} before do
Group.refresh_automatic_group!(:trust_level_2)
template = JSON.parse(File.open(
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
).read)
CustomWizard::Wizard.add_wizard(template)
@wizard = CustomWizard::Wizard.create('super_mega_fun_wizard', user)
end
it 'creates a topic' do it 'creates a topic' do
template['steps'][0]['fields'] = [text_field, textarea_field] built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
template['steps'][0]["actions"] = [create_topic_action] updater = built_wizard.create_updater(built_wizard.steps[0].id,
updater = run_update(template, nil, step_1_field_1: "Topic Title",
text: "Topic Title", step_1_field_2: "topic body"
textarea: "topic body" ).update
) updater2 = built_wizard.create_updater(built_wizard.steps[1].id, {}).update
topic = Topic.where(title: "Topic Title") topic = Topic.where(title: "Topic Title")
expect(topic.exists?).to eq(true) expect(topic.exists?).to eq(true)
@ -22,71 +32,102 @@ describe CustomWizard::Action do
end end
it 'sends a message' do it 'sends a message' do
fields = [text_field, textarea_field] User.create(username: 'angus1', email: "angus1@email.com")
if extra_field built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
fields.push(extra_field) built_wizard.create_updater(built_wizard.steps[0].id, {}).update
end built_wizard.create_updater(built_wizard.steps[1].id, {}).update
template['steps'][0]['fields'] = fields
template['steps'][0]["actions"] = [send_message_action.merge(extra_action_opts)]
run_update(template, nil,
text: "Message Title",
textarea: "message body"
)
topic = Topic.where( topic = Topic.where(
archetype: Archetype.private_message, archetype: Archetype.private_message,
title: "Message Title" title: "Message title"
) )
expect(topic.exists?).to eq(true) post = Post.where(
expect(
topic.first.topic_allowed_users.first.user.username
).to eq('angus')
expect(Post.where(
topic_id: topic.pluck(:id), topic_id: topic.pluck(:id),
raw: "message body" raw: "I will interpolate some wizard fields"
).exists?).to eq(true) )
expect(topic.exists?).to eq(true)
expect(topic.first.topic_allowed_users.first.user.username).to eq('angus1')
expect(post.exists?).to eq(true)
end end
it 'updates a profile' do it 'updates a profile' do
run_update(template, template['steps'][1]['id'], name: "Sally") built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
expect(user.name).to eq('Sally') upload = Upload.create!(
url: '/images/image.png',
original_filename: 'image.png',
filesize: 100,
user_id: -1,
)
steps = built_wizard.steps
built_wizard.create_updater(steps[0].id, {}).update
built_wizard.create_updater(steps[1].id,
step_2_field_7: upload.as_json,
).update
expect(user.profile_background_upload.id).to eq(upload.id)
end end
it 'opens a composer' do it 'opens a composer' do
template['steps'][0]['fields'] = [text_field, textarea_field] built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
template['steps'][0]["actions"] = [open_composer_action] built_wizard.create_updater(built_wizard.steps[0].id, step_1_field_1: "Text input").update
updater = run_update(template, nil, updater = built_wizard.create_updater(built_wizard.steps[1].id, {})
text: "Topic Title", updater.update
textarea: "topic body"
)
expect(updater.result.blank?).to eq(true) submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
category = Category.find_by(id: submissions.first['action_8'])
updater = run_update(template, template['steps'][1]['id']) expect(updater.result[:redirect_on_next]).to eq(
"/new-topic?title=Title%20of%20the%20composer%20topic&body=I%20am%20interpolating%20some%20user%20fields%20Angus%20angus%20angus@email.com&category=#{category.slug}/#{category.id}&tags=tag1"
expect(updater.result[:redirect_on_complete]).to eq(
"/new-topic?title=Topic%20Title&body=topic%20body"
) )
end end
it 'adds a user to a group' do it 'creates a category' do
template['steps'][0]['fields'] = [dropdown_groups_field] built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
template['steps'][0]["actions"] = [add_to_group_action] built_wizard.create_updater(built_wizard.steps[0].id, step_1_field_1: "Text input").update
built_wizard.create_updater(built_wizard.steps[1].id, {}).update
updater = run_update(template, nil, dropdown_groups: group.id) submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
expect(Category.where(id: submissions.first['action_8']).exists?).to eq(true)
end
it 'creates a group' do
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
step_id = built_wizard.steps[0].id
updater = built_wizard.create_updater(step_id, step_1_field_1: "Text input").update
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
expect(Group.where(name: submissions.first['action_9']).exists?).to eq(true)
end
it 'adds a user to a group' do
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
step_id = built_wizard.steps[0].id
updater = built_wizard.create_updater(step_id, step_1_field_1: "Text input").update
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
group = Group.find_by(name: submissions.first['action_9'])
expect(group.users.first.username).to eq('angus') expect(group.users.first.username).to eq('angus')
end end
it 'watches categories' do
built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
built_wizard.create_updater(built_wizard.steps[0].id, step_1_field_1: "Text input").update
built_wizard.create_updater(built_wizard.steps[1].id, {}).update
submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
expect(CategoryUser.where(
category_id: submissions.first['action_8'],
user_id: user.id
).first.notification_level).to eq(2)
expect(CategoryUser.where(
category_id: category.id,
user_id: user.id
).first.notification_level).to eq(0)
end
it 're-routes a user' do it 're-routes a user' do
template['steps'][0]["actions"] = [route_to_action] built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
updater = run_update(template, nil, {}) updater = built_wizard.create_updater(built_wizard.steps.last.id, {})
expect(updater.result[:redirect_on_next]).to eq( updater.update
"https://google.com" expect(updater.result[:redirect_on_complete]).to eq("https://google.com")
)
end end
end end

Datei anzeigen

@ -3,39 +3,19 @@
require 'rails_helper' require 'rails_helper'
describe CustomWizard::Builder do describe CustomWizard::Builder do
fab!(:user) { Fabricate(:user, username: 'angus') } fab!(:user) { Fabricate(:user, username: 'angus', email: "angus@email.com", trust_level: TrustLevel[2]) }
fab!(:trusted_user) { Fabricate(:user, trust_level: 3) } fab!(:new_user) { Fabricate(:user, trust_level: 0) }
fab!(:category1) { Fabricate(:category, name: 'cat1') } fab!(:category1) { Fabricate(:category, name: 'cat1') }
fab!(:category2) { Fabricate(:category, name: 'cat2') } fab!(:category2) { Fabricate(:category, name: 'cat2') }
fab!(:group) { Fabricate(:group) } fab!(:group) { Fabricate(:group) }
let!(:template) do before do
JSON.parse(File.open( Group.refresh_automatic_group!(:trust_level_2)
template = JSON.parse(File.open(
"#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json" "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json"
).read) ).read)
end CustomWizard::Wizard.add_wizard(template)
@wizard = CustomWizard::Wizard.create('super_mega_fun_wizard', user)
def build_wizard(t = template, u = user, build_opts = {}, params = {})
CustomWizard::Wizard.add_wizard(t)
CustomWizard::Builder.new('welcome', u).build(build_opts, params)
end
def add_submission_data(data = {})
PluginStore.set("welcome_submissions", user.id, {
name: 'Angus',
website: 'https://thepavilion.io'
}.merge(data))
end
def get_submission_data
PluginStore.get("welcome_submissions", user.id)
end
def run_update(t = template, step_id = nil, data = {})
wizard = build_wizard(t)
updater = wizard.create_updater(step_id || t['steps'][0]['id'], data)
updater.update
updater
end end
context 'disabled' do context 'disabled' do
@ -43,15 +23,8 @@ describe CustomWizard::Builder do
SiteSetting.custom_wizard_enabled = false SiteSetting.custom_wizard_enabled = false
end end
it "returns no steps" do it "returns nil" do
wizard = build_wizard expect(CustomWizard::Builder.new(@wizard.id, user).build).to eq(nil)
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)
end end
end end
@ -61,123 +34,164 @@ describe CustomWizard::Builder do
end end
it "returns steps" do it "returns steps" do
expect(build_wizard.steps.length).to eq(2) expect(
CustomWizard::Builder.new(@wizard.id, user).build.steps.length
).to eq(2)
end end
it 'returns no steps if multiple submissions are disabled and user has completed' do it 'returns no steps if multiple submissions are disabled and user has completed' do
wizard_template = CustomWizard::Wizard.find(@wizard.id)
wizard_template[:multiple_submissions] = false
CustomWizard::Wizard.save(wizard_template)
history_params = { history_params = {
action: UserHistory.actions[:custom_wizard_step], action: UserHistory.actions[:custom_wizard_step],
acting_user_id: user.id, acting_user_id: user.id,
context: template['id'] context: @wizard.id
} }
UserHistory.create!(history_params.merge(subject: template['steps'][0]['id'])) @wizard.steps.each do |step|
UserHistory.create!(history_params.merge(subject: template['steps'][1]['id'])) UserHistory.create!(history_params.merge(subject: step.id))
end
template["multiple_submissions"] = false built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
expect(build_wizard(template).steps.length).to eq(0) expect(
CustomWizard::Builder.new(@wizard.id, user).build.steps.length
).to eq(0)
end end
it 'returns no steps if user is not permitted' do it 'returns no steps if user is not permitted' do
template["min_trust"] = 3 expect(
expect(build_wizard(template).steps.length).to eq(0) CustomWizard::Builder.new(@wizard.id, new_user).build.steps.length
).to eq(0)
end end
it 'returns steps if user is permitted' do it 'returns steps if user is permitted' do
template["min_trust"] = 3 expect(
expect(build_wizard(template, trusted_user).steps.length).to eq(2) CustomWizard::Builder.new(@wizard.id, user).build.steps.length
).to eq(3)
end end
it 'returns a wizard with prefilled data if user has partially completed it' do it 'returns a wizard with prefilled data if user has partially completed it' do
add_submission_data expect(
wizard = build_wizard CustomWizard::Builder.new(@wizard.id, user)
expect(wizard.steps[0].fields.first.value).to eq('Angus') .build
expect(wizard.steps[1].fields.first.value).to eq('https://thepavilion.io') .steps[0].fields[0].value
).to eq('I am prefilled')
end end
it 'returns a wizard with no prefilled data if options include reset' do it 'returns a wizard with no prefilled data if options include reset' do
add_submission_data PluginStore.set("super_mega_fun_wizard_submissions", user.id, {
wizard = build_wizard(template, user, reset: true) text: 'Input into text',
expect(wizard.steps[0].fields.first.value).to eq(nil) })
expect(wizard.steps[1].fields.first.value).to eq(nil) expect(
CustomWizard::Builder.new(@wizard.id, user)
.build(reset: true)
.steps[0].fields[0].value
).to eq(nil)
end end
context 'building steps' do context 'building steps' do
it 'returns step metadata' do it 'returns step metadata' do
expect(build_wizard.steps[0].title).to eq('Welcome to Pavilion') expect(
expect(build_wizard.steps[1].title).to eq('Tell us about you') CustomWizard::Builder.new(@wizard.id, user)
.build(reset: true)
.steps[0]
).to eq('Super Mega Fun Wizard')
end end
it 'saves permitted params' do it 'saves permitted params' do
template['steps'][0]['permitted_params'] = permitted_params @wizard.steps[0].permitted_params = permitted_params
wizard = build_wizard(template, user, {}, param_key: 'param_value') built_wizard = CustomWizard::Builder.new(@wizard.id, user).build({}, param_key: 'param_value')
submissions = get_submission_data submissions = PluginStore.get("super_mega_fun_wizard_submissions", user.id)
expect(submissions.first['submission_param_key']).to eq('param_value') expect(submissions[0]['submission_param_key']).to eq('param_value')
end end
it 'is not permitted if required data is not present' do it 'is not permitted if required data is not present' do
template['steps'][0]['required_data'] = required_data @wizard.steps[0].required_data = required_data
expect(build_wizard(template, user).steps[0].permitted).to eq(false) expect(
CustomWizard::Builder.new(@wizard.id, user).build.steps[0].permitted
).to eq(false)
end end
it 'it shows required data message if required data has message' do it 'it shows required data message if required data has message' do
template['steps'][0]['required_data'] = required_data @wizard.steps[0].required_data = required_data
template['steps'][0]['required_data_message'] = required_data_message @wizard.steps[0].required_data_message = "Data is required"
add_submission_data(nickname: "John") PluginStore.set("super_mega_fun_wizard_submissions", user.id,
wizard = build_wizard(template, user) text: 'Input into text',
expect(wizard.steps[0].permitted).to eq(false) )
expect(wizard.steps[0].permitted_message).to eq(required_data_message) built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
expect(built_wizard.steps[0].permitted).to eq(false)
expect(built_wizard.steps[0].permitted_message).to eq("Data is required")
end end
it 'is permitted if required data is present' do it 'is permitted if required data is present' do
template['steps'][0]['required_data'] = required_data @wizard.steps[0].required_data = required_data
PluginStore.set('welcome_submissions', user.id, nickname: "Angus", name: "Angus") PluginStore.set('super_mega_fun_wizard_submissions', user.id,
expect(build_wizard(template, user).steps[0].permitted).to eq(true) text: "Input into text"
)
expect(
CustomWizard::Builder.new(@wizard.id, user).build.steps[0].permitted
).to eq(true)
end end
it 'returns field metadata' do it 'returns field metadata' do
expect(build_wizard(template, user).steps[0].fields[0].label).to eq("<p>Name</p>") built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
expect(build_wizard(template, user).steps[0].fields[0].type).to eq("text") expect(built_wizard.steps[0].fields[0].label).to eq("<p>Name</p>")
expect(built_wizard.steps[0].fields[0].type).to eq("text")
end end
it 'returns fields' do it 'returns fields' do
template['steps'][0]['fields'][1] = checkbox_field @wizard.steps[0].fields[1] = checkbox_field
expect(build_wizard(template, user).steps[0].fields.length).to eq(2) built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
expect(built_wizard.steps[0].fields.length).to eq(2)
end end
end end
context 'on update' do context 'on update' do
it 'saves submissions' do it 'saves submissions' do
run_update(template, nil, name: 'Angus') built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
expect(get_submission_data.first['name']).to eq('Angus') built_wizard.create_updater(built_wizard.steps[0].id,
step_1_field_1: 'Text input'
).update
expect(
PluginStore.get("super_mega_fun_wizard_submissions", user.id)
.first['step_1_field_1']
).to eq('Text input')
end end
context 'validation' do context 'validation' do
it 'applies min length' do it 'applies min length' do
template['steps'][0]['fields'][0]['min_length'] = 10 @wizard.steps[0].fields[0].min_length = 10
updater = run_update(template, nil, name: 'short') built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
expect(updater.errors.messages[:name].first).to eq( updater = built_wizard.create_updater(built_wizard.steps[0].id,
I18n.t('wizard.field.too_short', label: 'Name', min: 10) step_1_field_1: 'Te'
).update
expect(updater.errors.messages[:text].first).to eq(
I18n.t('wizard.field.too_short', label: 'Text', min: 3)
) )
end end
it 'standardises boolean entries' do it 'standardises boolean entries' do
template['steps'][0]['fields'][0] = checkbox_field @wizard.steps[0].fields[0] = checkbox_field
run_update(template, nil, checkbox: 'false') built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
expect(get_submission_data.first['checkbox']).to eq(false) updater = built_wizard.create_updater(built_wizard.steps[1].id,
step_2_field_5: 'false'
).update
expect(
PluginStore.get("super_mega_fun_wizard_submissions", user.id)
.first['step_2_field_5']
).to eq(false)
end end
it 'requires required fields' do it 'requires required fields' do
template['steps'][0]['fields'][0]['required'] = true @wizard.steps[0].fields[0]['required'] = true
expect(run_update(template).errors.messages[:name].first).to eq( built_wizard = CustomWizard::Builder.new(@wizard.id, user).build
I18n.t('wizard.field.required', label: 'Name') updater = built_wizard.create_updater(built_wizard.steps.second.id).update
) expect(
updater.errors.messages[:step_1_field_1].first
).to eq(I18n.t('wizard.field.required', label: 'Text'))
end end
end end
it 'runs actions attached to a step' do
run_update(template, template['steps'][1]['id'], name: "Gus")
expect(user.name).to eq('Gus')
end
end end
end end
end end

Datei anzeigen

@ -1,14 +0,0 @@
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,
{}
)
).to eq('My name is Angus')
end

Datei anzeigen

@ -1,49 +1,525 @@
{ {
"id": "welcome", "id": "super_mega_fun_wizard",
"name": "Welcome", "name": "Super Mega Fun Wizard",
"background": "#006da3", "background": "#333333",
"save_submissions": true, "save_submissions": true,
"multiple_submissions": true, "multiple_submissions": true,
"after_signup": true, "after_signup": false,
"min_trust": 1, "prompt_completion": true,
"theme_id": 4, "theme_id": 2,
"permitted": [
{
"type": "assignment",
"output_type": "group",
"output_connector": "set",
"output": [
12
]
}
],
"steps": [ "steps": [
{ {
"id": "welcome", "id": "step_1",
"title": "Welcome to Pavilion", "title": "Text",
"raw_description": "Hey there, thanks for signing up.\n\nWe're Pavilion, an international freelancer cooperative that specialises in online communities.\n\nThis site is our own community, where we work with our clients, users of our open source work and our broader community.\n\n", "raw_description": "Text inputs!",
"description": "<p>Hey there, thanks for signing up.</p>\n<p>Were Pavilion, an international freelancer cooperative that specialises in online communities.</p>\n<p>This site is our own community, where we work with our clients, users of our open source work and our broader community.</p>",
"fields": [ "fields": [
{ {
"id": "name", "id": "step_1_field_1",
"label": "Text",
"type": "text", "type": "text",
"label": "Name" "min_length": "3",
"prefill": [
{
"type": "assignment",
"output": "I am prefilled",
"output_type": "text",
"output_connector": "set"
}
]
},
{
"id": "step_1_field_2",
"label": "Textarea",
"type": "textarea",
"min_length": ""
},
{
"id": "step_1_field_3",
"label": "Composer",
"type": "composer"
},
{
"id": "step_1_field_4",
"label": "I'm only text",
"description": "",
"type": "text_only"
}
],
"description": "<p>Text inputs!</p>"
},
{
"id": "step_2",
"title": "Values",
"raw_description": "Because I couldn't think of another name for this step :)",
"fields": [
{
"id": "step_2_field_1",
"label": "Date",
"type": "date",
"format": "YYYY-MM-DD"
},
{
"id": "step_2_field_2",
"label": "Time",
"type": "time",
"format": "HH:mm"
},
{
"id": "step_2_field_3",
"label": "Date & Time",
"type": "date_time",
"format": ""
},
{
"id": "step_2_field_4",
"label": "Number",
"type": "number"
},
{
"id": "step_2_field_5",
"label": "Checkbox",
"type": "checkbox"
},
{
"id": "step_2_field_7",
"label": "Upload",
"type": "upload",
"file_types": ".jpg,.png"
}
],
"description": "<p>Because I couldnt think of another name for this step <img src=\"/images/emoji/twitter/slight_smile.png?v=9\" title=\":slight_smile:\" class=\"emoji\" alt=\":slight_smile:\"></p>"
},
{
"id": "step_3",
"title": "Combo-boxes",
"raw_description": "Unfortunately not the edible type :sushi: ",
"fields": [
{
"id": "step_3_field_1",
"label": "Custom Dropdown",
"type": "dropdown",
"content": [
{
"type": "association",
"pairs": [
{
"index": 0,
"key": "choice1",
"key_type": "text",
"value": "Choice 1",
"value_type": "text",
"connector": "equal"
},
{
"index": 1,
"key": "choice2",
"key_type": "text",
"value": "Choice 2",
"value_type": "text",
"connector": "association"
},
{
"index": 2,
"key": "choice3",
"key_type": "text",
"value": "Choice 3",
"value_type": "text",
"connector": "association"
}
]
}
]
},
{
"id": "step_3_field_2",
"label": "Tag",
"type": "tag"
},
{
"id": "step_3_field_3",
"label": "Category",
"type": "category",
"limit": 1,
"property": "id"
},
{
"id": "step_3_field_4",
"label": "Group",
"type": "group"
},
{
"id": "step_3_field_5",
"label": "User Selector",
"description": "",
"type": "user_selector"
}
],
"description": "<p>Unfortunately not the edible type <img src=\"/images/emoji/twitter/sushi.png?v=9\" title=\":sushi:\" class=\"emoji\" alt=\":sushi:\"></p>"
}
],
"actions": [
{
"id": "action_9",
"run_after": "step_1",
"type": "create_group",
"title": [
{
"type": "assignment",
"output": "New Group Member",
"output_type": "text",
"output_connector": "set"
}
],
"custom_fields": [
{
"type": "association",
"pairs": [
{
"index": 0,
"key": "group_custom_field",
"key_type": "text",
"value": "step_3_field_1",
"value_type": "wizard_field",
"connector": "association"
}
]
}
],
"name": [
{
"type": "assignment",
"output": "step_1_field_1",
"output_type": "wizard_field",
"output_connector": "set"
}
],
"full_name": [
{
"type": "assignment",
"output": "step_1_field_1",
"output_type": "wizard_field",
"output_connector": "set"
}
],
"usernames": [
{
"type": "assignment",
"output_type": "user",
"output_connector": "set",
"output": [
"angus1"
]
}
],
"owner_usernames": [
{
"type": "assignment",
"output_type": "user",
"output_connector": "set",
"output": [
"angus"
]
}
],
"grant_trust_level": [
{
"type": "assignment",
"output": "3",
"output_type": "text",
"output_connector": "set"
}
],
"mentionable_level": [
{
"type": "assignment",
"output": "1",
"output_type": "text",
"output_connector": "set"
}
],
"messageable_level": [
{
"type": "assignment",
"output": "2",
"output_type": "text",
"output_connector": "set"
}
],
"visibility_level": [
{
"type": "assignment",
"output": "3",
"output_type": "text",
"output_connector": "set"
}
],
"members_visibility_level": [
{
"type": "assignment",
"output": "99",
"output_type": "text",
"output_connector": "set"
} }
] ]
}, },
{ {
"id": "about_you", "id": "action_6",
"title": "Tell us about you", "run_after": "step_1",
"raw_description": "We'd like to know a little more about you. Add a your name and your website below. This will update your user profile.", "type": "add_to_group",
"description": "<p>Wed like to know a little more about you. Add a your name and your website below. This will update your user profile.</p>", "group": [
"fields": [
{ {
"id": "website", "type": "assignment",
"label": "Website", "output": "action_9",
"type": "text" "output_type": "wizard_action",
"output_connector": "set"
} }
], ]
"actions": [ },
{
"id": "action_8",
"run_after": "step_1",
"type": "create_category",
"custom_fields": [
{ {
"id": "update_profile", "type": "association",
"type": "update_profile", "pairs": [
"profile_updates": [
{ {
"key": "name", "index": 0,
"value": "name" "key": "category_custom_field",
"key_type": "text",
"value": "CC Val",
"value_type": "text",
"connector": "association"
} }
] ]
} }
],
"name": [
{
"type": "assignment",
"output": "step_1_field_1",
"output_type": "wizard_field",
"output_connector": "set"
}
],
"slug": [
{
"type": "assignment",
"output": "step_1_field_1",
"output_type": "wizard_field",
"output_connector": "set"
}
],
"permissions": [
{
"type": "association",
"pairs": [
{
"index": 0,
"key": "action_9",
"key_type": "wizard_action",
"value": "2",
"value_type": "text",
"connector": "association"
}
]
}
]
},
{
"id": "action_5",
"run_after": "step_1",
"type": "watch_categories",
"notification_level": "tracking",
"wizard_user": true,
"categories": [
{
"type": "assignment",
"output": "action_8",
"output_type": "wizard_action",
"output_connector": "set"
}
],
"mute_remainder": [
{
"type": "assignment",
"output": "true",
"output_type": "text",
"output_connector": "set"
}
]
},
{
"id": "action_1",
"run_after": "step_2",
"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"
}
] ]
} }
] ]

Datei anzeigen

@ -1,49 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
describe CustomWizardSerializer 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)
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)
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)
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)
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)
end
end

Datei anzeigen

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

@ -0,0 +1,45 @@
# 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::Wizard.add_wizard(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