diff --git a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 b/assets/javascripts/discourse/components/wizard-custom-action.js.es6 index a04ff563..b0831d5d 100644 --- a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 +++ b/assets/javascripts/discourse/components/wizard-custom-action.js.es6 @@ -1,6 +1,6 @@ import { default as discourseComputed } from "discourse-common/utils/decorators"; import wizardSchema from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-schema"; -import { and, empty, equal, or } from "@ember/object/computed"; +import { empty, equal, or } from "@ember/object/computed"; import { notificationLevels, selectKitContent } from "../lib/wizard"; import { computed } from "@ember/object"; import UndoChanges from "../mixins/undo-changes"; diff --git a/assets/javascripts/discourse/lib/wizard-schema.js.es6 b/assets/javascripts/discourse/lib/wizard-schema.js.es6 index 613e6569..2e810634 100644 --- a/assets/javascripts/discourse/lib/wizard-schema.js.es6 +++ b/assets/javascripts/discourse/lib/wizard-schema.js.es6 @@ -197,9 +197,9 @@ const action = { required: ["id", "type"], proTypes: [ 'send_message', + 'add_to_group', 'create_category', 'create_group', - 'watch_categories', 'send_to_api' ], dependent: {}, diff --git a/controllers/custom_wizard/admin/pro.rb b/controllers/custom_wizard/admin/pro.rb index 15e9e50f..70e5de04 100644 --- a/controllers/custom_wizard/admin/pro.rb +++ b/controllers/custom_wizard/admin/pro.rb @@ -10,7 +10,7 @@ class CustomWizard::AdminProController < CustomWizard::AdminController def authorize request_id = SecureRandom.hex(32) cookies[:user_api_request_id] = request_id - redirect_to pro.authentication_request(current_user.id, request_id).to_s + redirect_to pro.authentication_url(current_user.id, request_id).to_s end def authorize_callback diff --git a/controllers/custom_wizard/wizard.rb b/controllers/custom_wizard/wizard.rb index 804fc422..78f2fd4a 100644 --- a/controllers/custom_wizard/wizard.rb +++ b/controllers/custom_wizard/wizard.rb @@ -5,7 +5,7 @@ class CustomWizard::WizardController < ::ApplicationController layout 'wizard' before_action :ensure_plugin_enabled - before_action :update_pro_subscription + before_action :update_pro_subscription, only: [:index] helper_method :wizard_page_title helper_method :wizard_theme_id helper_method :wizard_theme_lookup diff --git a/coverage/.last_run.json b/coverage/.last_run.json index 2d4d0378..cff5740b 100644 --- a/coverage/.last_run.json +++ b/coverage/.last_run.json @@ -1,5 +1,5 @@ { "result": { - "line": 91.83 + "line": 91.96 } } diff --git a/jobs/scheduled/update_pro_subscription.rb b/jobs/scheduled/update_pro_subscription.rb index d00b2560..773093b0 100644 --- a/jobs/scheduled/update_pro_subscription.rb +++ b/jobs/scheduled/update_pro_subscription.rb @@ -3,7 +3,7 @@ class CustomWizard::UpdateProSubscription < ::Jobs::Scheduled every 1.hour - def execute(args) + def execute(args={}) CustomWizard::Pro.update_subscription end end \ No newline at end of file diff --git a/lib/custom_wizard/builder.rb b/lib/custom_wizard/builder.rb index 2ecdf12d..99370f19 100644 --- a/lib/custom_wizard/builder.rb +++ b/lib/custom_wizard/builder.rb @@ -72,6 +72,23 @@ class CustomWizard::Builder @wizard end + def check_condition(template) + if template['condition'].present? + result = CustomWizard::Mapper.new( + inputs: template['condition'], + user: @wizard.user, + data: @wizard.current_submission&.fields_and_meta, + opts: { + multiple: true + } + ).perform + + result.any? + else + true + end + end + private def mapper @@ -224,23 +241,6 @@ class CustomWizard::Builder end end - def check_condition(template) - if template['condition'].present? - result = CustomWizard::Mapper.new( - inputs: template['condition'], - user: @wizard.user, - data: @wizard.current_submission&.fields_and_meta, - opts: { - multiple: true - } - ).perform - - result.any? - else - true - end - end - def check_if_permitted(step, step_template) step.permitted = true diff --git a/lib/custom_wizard/mapper.rb b/lib/custom_wizard/mapper.rb index b418b4b9..6700e37d 100644 --- a/lib/custom_wizard/mapper.rb +++ b/lib/custom_wizard/mapper.rb @@ -252,7 +252,7 @@ class CustomWizard::Mapper end end - if @pro.subscribed? && opts[:template] + if opts[:template] && @pro.subscribed? template = Liquid::Template.parse(string) string = template.render(data) end diff --git a/lib/custom_wizard/pro.rb b/lib/custom_wizard/pro.rb index 3726e9b4..5a813e21 100644 --- a/lib/custom_wizard/pro.rb +++ b/lib/custom_wizard/pro.rb @@ -54,24 +54,27 @@ class CustomWizard::Pro return false unless data && data.is_a?(Hash) subscriptions = data[:subscriptions] - if subscriptions.present? - subscription = subscriptions.first - type = subscription[:price_nickname] - + if subscriptions.present? && type = subscriptions.first[:price_nickname] @subscription = set_subscription(type) return true end end end - remove_subscription + destroy_subscription + false end def destroy_subscription - remove_subscription + if remove_subscription + @subscription = CustomWizard::ProSubscription.new(get_subscription) + !@subscription.active? + else + false + end end - def authentication_request(user_id, request_id) + def authentication_url(user_id, request_id) keys = @authentication.generate_keys(user_id, request_id) params = { public_key: keys.public_key, @@ -89,7 +92,7 @@ class CustomWizard::Pro def authentication_response(request_id, payload) data = @authentication.decrypt_payload(request_id, payload) - return unless data.is_a?(Hash) && data[:key] && data[:user_id] + return false unless data.is_a?(Hash) && data[:key] && data[:user_id] api_key = data[:key] user_id = data[:user_id] @@ -104,13 +107,26 @@ class CustomWizard::Pro end def destroy_authentication - remove_authentication + if remove_authentication + @authentication = CustomWizard::ProAuthentication.new(get_authentication) + !@authentication.active? + else + false + end end def self.subscribed? self.new.subscribed? end + def self.authorized? + self.new.authorized? + end + + def self.update_subscription + self.new.update_subscription + end + def self.namespace "custom_wizard_pro" end @@ -165,5 +181,6 @@ class CustomWizard::Pro def remove_authentication PluginStore.remove(self.class.namespace, authentication_db_key) + get_authentication end end \ No newline at end of file diff --git a/lib/custom_wizard/pro/authentication.rb b/lib/custom_wizard/pro/authentication.rb index 0f3546eb..8d96a017 100644 --- a/lib/custom_wizard/pro/authentication.rb +++ b/lib/custom_wizard/pro/authentication.rb @@ -30,11 +30,13 @@ class CustomWizard::ProAuthentication def decrypt_payload(request_id, payload) keys = get_keys(request_id) + return false unless keys.present? && keys.pem delete_keys(request_id) rsa = OpenSSL::PKey::RSA.new(keys.pem) decrypted_payload = rsa.private_decrypt(Base64.decode64(payload)) + return false unless decrypted_payload.present? begin @@ -48,7 +50,16 @@ class CustomWizard::ProAuthentication data end - + + def get_keys(request_id) + raw = PluginStore.get(CustomWizard::Pro.namespace, "#{keys_db_key}_#{request_id}") + OpenStruct.new( + user_id: raw && raw['user_id'], + pem: raw && raw['pem'], + nonce: raw && raw['nonce'] + ) + end + private def keys_db_key @@ -67,15 +78,6 @@ class CustomWizard::ProAuthentication ) end - def get_keys(request_id) - raw = PluginStore.get(CustomWizard::Pro.namespace, "#{keys_db_key}_#{request_id}") - OpenStruct.new( - user_id: raw && raw['user_id'], - pem: raw && raw['pem'], - nonce: raw && raw['nonce'] - ) - end - def delete_keys(request_id) PluginStore.remove(CustomWizard::Pro.namespace, "#{keys_db_key}_#{request_id}") end diff --git a/lib/custom_wizard/validators/template.rb b/lib/custom_wizard/validators/template.rb index 0f5f686c..839a070f 100644 --- a/lib/custom_wizard/validators/template.rb +++ b/lib/custom_wizard/validators/template.rb @@ -21,8 +21,8 @@ class CustomWizard::TemplateValidator check_required(step, :step) validate_pro(step, :step) - if data[:fields].present? - data[:fields].each do |field| + if step[:fields].present? + step[:fields].each do |field| validate_pro(field, :field) check_required(field, :field) end @@ -66,9 +66,9 @@ class CustomWizard::TemplateValidator action: { type: %w[ send_message + add_to_group create_category create_group - watch_categories send_to_api ] } @@ -87,11 +87,13 @@ class CustomWizard::TemplateValidator def validate_pro(object, type) self.class.pro[type].each do |property, pro_type| - is_pro = (pro_type === 'present' && object[property].present?) || - (pro_type === 'conditional' && object[property].is_a?(Hash)) || - (pro_type.is_a?(Array) && pro_type.includes?(object[property])) + is_pro = object[property.to_s].present? && ( + pro_type === 'present' || + (pro_type === 'conditional' && object[property.to_s].is_a?(Hash)) || + (pro_type.is_a?(Array) && pro_type.include?(object[property.to_s])) + ) - if is_pro && @pro.subscribed? + if is_pro && !@pro.subscribed? errors.add :base, I18n.t("wizard.validation.pro", type: type.to_s, property: property) end end diff --git a/lib/custom_wizard/wizard.rb b/lib/custom_wizard/wizard.rb index 8f5a897f..cd59f361 100644 --- a/lib/custom_wizard/wizard.rb +++ b/lib/custom_wizard/wizard.rb @@ -308,10 +308,10 @@ class CustomWizard::Wizard end end - def self.list(user, template_opts: {}, not_completed: false) + def self.list(user, template_opts = {}, not_completed = false) return [] unless user - CustomWizard::Template.list(template_opts).reduce([]) do |result, template| + CustomWizard::Template.list(**template_opts).reduce([]) do |result, template| wizard = new(template, user) result.push(wizard) if wizard.can_access? && ( !not_completed || !wizard.completed? @@ -323,7 +323,7 @@ class CustomWizard::Wizard def self.after_signup(user) wizards = list( user, - template_opts: { + { setting: 'after_signup', order: "(value::json ->> 'permitted') IS NOT NULL DESC" } @@ -334,11 +334,11 @@ class CustomWizard::Wizard def self.prompt_completion(user) wizards = list( user, - template_opts: { + { setting: 'prompt_completion', order: "(value::json ->> 'permitted') IS NOT NULL DESC" }, - not_completed: true + true ) if wizards.any? wizards.map do |w| diff --git a/spec/components/custom_wizard/action_spec.rb b/spec/components/custom_wizard/action_spec.rb index 8b617c39..438f29dd 100644 --- a/spec/components/custom_wizard/action_spec.rb +++ b/spec/components/custom_wizard/action_spec.rb @@ -6,26 +6,22 @@ describe CustomWizard::Action do fab!(:category) { Fabricate(:category, name: 'cat1', slug: 'cat-slug') } fab!(:group) { Fabricate(:group) } - let(:wizard_template) { - JSON.parse( - File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json" - ).read - ) - } + let(:wizard_template) { get_wizard_fixture("wizard") } + let(:open_composer) { get_wizard_fixture("actions/open_composer") } + let(:create_category) { get_wizard_fixture("actions/create_category") } + let(:create_group) { get_wizard_fixture("actions/create_group") } + let(:add_to_group) { get_wizard_fixture("actions/add_to_group") } + let(:send_message) { get_wizard_fixture("actions/send_message") } + let(:send_message_multi) { get_wizard_fixture("actions/send_message_multi") } - let(:open_composer) { - JSON.parse( - File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/actions/open_composer.json" - ).read - ) - } + def update_template(template) + CustomWizard::Template.save(template, skip_jobs: true) + @template = CustomWizard::Template.find('super_mega_fun_wizard') + end before do Group.refresh_automatic_group!(:trust_level_2) - CustomWizard::Template.save(wizard_template, skip_jobs: true) - @template = CustomWizard::Template.find('super_mega_fun_wizard') + update_template(wizard_template) end context 'creating a topic' do @@ -110,54 +106,6 @@ describe CustomWizard::Action do end end - context 'sending a message' do - it 'works' do - User.create(username: 'angus1', email: "angus1@email.com") - - wizard = CustomWizard::Builder.new(@template[:id], user).build - wizard.create_updater(wizard.steps[0].id, {}).update - wizard.create_updater(wizard.steps[1].id, {}).update - - topic = Topic.where( - archetype: Archetype.private_message, - title: "Message title" - ) - - post = Post.where( - topic_id: topic.pluck(:id), - raw: "I will interpolate some wizard fields" - ) - - expect(topic.exists?).to eq(true) - expect(topic.first.topic_allowed_users.first.user.username).to eq('angus1') - expect(post.exists?).to eq(true) - end - - it 'allows using multiple PM targets' do - User.create(username: 'angus1', email: "angus1@email.com") - User.create(username: 'faiz', email: "faiz@email.com") - Group.create(name: "cool_group") - Group.create(name: 'cool_group_1') - wizard = CustomWizard::Builder.new(@template[:id], user).build - wizard.create_updater(wizard.steps[0].id, {}).update - wizard.create_updater(wizard.steps[1].id, {}).update - - topic = Topic.where( - archetype: Archetype.private_message, - title: "Multiple Recipients title" - ) - - post = Post.where( - topic_id: topic.pluck(:id), - raw: "I will interpolate some wizard fields" - ) - expect(topic.exists?).to eq(true) - expect(topic.first.all_allowed_users.map(&:username)).to include('angus1', 'faiz') - expect(topic.first.allowed_groups.map(&:name)).to include('cool_group', 'cool_group_1') - expect(post.exists?).to eq(true) - end - end - it 'updates a profile' do wizard = CustomWizard::Builder.new(@template[:id], user).build upload = Upload.create!( @@ -182,10 +130,8 @@ describe CustomWizard::Action do updater = wizard.create_updater(wizard.steps[1].id, {}) updater.update - category = Category.find_by(id: wizard.current_submission.fields['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%40email.com&category_id=#{category.id}&tags=tag1" + "/new-topic?title=Title%20of%20the%20composer%20topic&body=I%20am%20interpolating%20some%20user%20fields%20Angus%20angus%20angus%40email.com&tags=tag1" ) end @@ -210,35 +156,11 @@ describe CustomWizard::Action do end end - it 'creates a category' do - wizard = CustomWizard::Builder.new(@template[:id], user).build - wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update - wizard.create_updater(wizard.steps[1].id, {}).update - expect(Category.where(id: wizard.current_submission.fields['action_8']).exists?).to eq(true) - end - - it 'creates a group' do - wizard = CustomWizard::Builder.new(@template[:id], user).build - wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update - expect(Group.where(name: wizard.current_submission.fields['action_9']).exists?).to eq(true) - end - - it 'adds a user to a group' do - wizard = CustomWizard::Builder.new(@template[:id], user).build - step_id = wizard.steps[0].id - updater = wizard.create_updater(step_id, step_1_field_1: "Text input").update - group = Group.find_by(name: wizard.current_submission.fields['action_9']) - expect(group.users.first.username).to eq('angus') - end - it 'watches categories' do wizard = CustomWizard::Builder.new(@template[:id], user).build wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update wizard.create_updater(wizard.steps[1].id, {}).update - expect(CategoryUser.where( - category_id: wizard.current_submission.fields['action_8'], - user_id: user.id - ).first.notification_level).to eq(2) + expect(CategoryUser.where( category_id: category.id, user_id: user.id @@ -251,4 +173,97 @@ describe CustomWizard::Action do updater.update expect(updater.result[:redirect_on_next]).to eq("https://google.com") end + + context "pro actions" do + before do + enable_pro + end + + it '#send_message' do + wizard_template['actions'] << send_message + update_template(wizard_template) + + User.create(username: 'angus1', email: "angus1@email.com") + + wizard = CustomWizard::Builder.new(@template[:id], user).build + wizard.create_updater(wizard.steps[0].id, {}).update + wizard.create_updater(wizard.steps[1].id, {}).update + + topic = Topic.where( + archetype: Archetype.private_message, + title: "Message title" + ) + + post = Post.where( + topic_id: topic.pluck(:id), + raw: "I will interpolate some wizard fields" + ) + + expect(topic.exists?).to eq(true) + expect(topic.first.topic_allowed_users.first.user.username).to eq('angus1') + expect(post.exists?).to eq(true) + end + + it '#send_message allows using multiple targets' do + wizard_template['actions'] << send_message_multi + update_template(wizard_template) + + User.create(username: 'angus1', email: "angus1@email.com") + User.create(username: 'faiz', email: "faiz@email.com") + Group.create(name: "cool_group") + Group.create(name: 'cool_group_1') + wizard = CustomWizard::Builder.new(@template[:id], user).build + wizard.create_updater(wizard.steps[0].id, {}).update + wizard.create_updater(wizard.steps[1].id, {}).update + + topic = Topic.where( + archetype: Archetype.private_message, + title: "Multiple Recipients title" + ) + + post = Post.where( + topic_id: topic.pluck(:id), + raw: "I will interpolate some wizard fields" + ) + + expect(topic.exists?).to eq(true) + expect(topic.first.all_allowed_users.map(&:username)).to include('angus1', 'faiz') + expect(topic.first.allowed_groups.map(&:name)).to include('cool_group', 'cool_group_1') + expect(post.exists?).to eq(true) + end + + it '#create_category' do + wizard_template['actions'] << create_category + update_template(wizard_template) + + wizard = CustomWizard::Builder.new(@template[:id], user).build + wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update + wizard.create_updater(wizard.steps[1].id, {}).update + + expect(Category.where(id: wizard.current_submission.fields['action_8']).exists?).to eq(true) + end + + it '#create_group' do + wizard_template['actions'] << create_group + update_template(wizard_template) + + wizard = CustomWizard::Builder.new(@template[:id], user).build + wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update + + expect(Group.where(name: wizard.current_submission.fields['action_9']).exists?).to eq(true) + end + + it '#add_to_group' do + wizard_template['actions'] << create_group + wizard_template['actions'] << add_to_group + update_template(wizard_template) + + wizard = CustomWizard::Builder.new(@template[:id], user).build + step_id = wizard.steps[0].id + updater = wizard.create_updater(step_id, step_1_field_1: "Text input").update + group = Group.find_by(name: wizard.current_submission.fields['action_9']) + + expect(group.users.first.username).to eq('angus') + end + end end diff --git a/spec/components/custom_wizard/builder_spec.rb b/spec/components/custom_wizard/builder_spec.rb index 8e80d806..19be5830 100644 --- a/spec/components/custom_wizard/builder_spec.rb +++ b/spec/components/custom_wizard/builder_spec.rb @@ -15,45 +15,15 @@ describe CustomWizard::Builder do fab!(:category2) { Fabricate(:category, name: 'cat2') } fab!(:group) { Fabricate(:group) } - let(:required_data_json) { - JSON.parse( - File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/step/required_data.json" - ).read - ) - } - - let(:permitted_json) { - JSON.parse( - File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/permitted.json" - ).read - ) - } - - let(:permitted_param_json) { - JSON.parse( - File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/step/permitted_params.json" - ).read - ) - } - - let(:user_condition_json) { - JSON.parse( - File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/condition/user_condition.json" - ).read - ) - } + let(:wizard_template) { get_wizard_fixture("wizard") } + let(:required_data_json) { get_wizard_fixture("step/required_data") } + let(:permitted_json) { get_wizard_fixture("wizard/permitted") } + let(:permitted_param_json) { get_wizard_fixture("step/permitted_params") } + let(:user_condition_json) { get_wizard_fixture("condition/user_condition") } before do Group.refresh_automatic_group!(:trust_level_3) - CustomWizard::Template.save( - JSON.parse(File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json" - ).read), - skip_jobs: true) + CustomWizard::Template.save(wizard_template, skip_jobs: true) @template = CustomWizard::Template.find('super_mega_fun_wizard') end @@ -281,8 +251,9 @@ describe CustomWizard::Builder do end end - context "with condition" do + context "with condition" do before do + enable_pro @template[:steps][0][:condition] = user_condition_json['condition'] CustomWizard::Template.save(@template.as_json) end @@ -321,6 +292,7 @@ describe CustomWizard::Builder do context "with condition" do before do + enable_pro @template[:steps][0][:fields][0][:condition] = user_condition_json['condition'] CustomWizard::Template.save(@template.as_json) end diff --git a/spec/components/custom_wizard/custom_field_spec.rb b/spec/components/custom_wizard/custom_field_spec.rb index b17e26c6..fb1799dd 100644 --- a/spec/components/custom_wizard/custom_field_spec.rb +++ b/spec/components/custom_wizard/custom_field_spec.rb @@ -3,12 +3,8 @@ require_relative '../../plugin_helper' describe CustomWizard::CustomField do - - let(:custom_field_json) { - JSON.parse(File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/custom_field/custom_fields.json" - ).read) - } + let(:custom_field_json) { get_wizard_fixture("custom_field/custom_fields") } + let(:custom_field_pro_json) { get_wizard_fixture("custom_field/pro_custom_fields") } before do CustomWizard::CustomField.invalidate_cache @@ -104,8 +100,8 @@ describe CustomWizard::CustomField do it "does not save with an unsupported serializer" do invalid_field_json = custom_field_json['custom_fields'].first - invalid_field_json['klass'] = 'category' - invalid_field_json['serializers'] = ['category', 'site_category'] + invalid_field_json['klass'] = 'post' + invalid_field_json['serializers'] = ['post', 'post_revision'] custom_field = CustomWizard::CustomField.new(nil, invalid_field_json) @@ -113,8 +109,8 @@ describe CustomWizard::CustomField do expect(custom_field.valid?).to eq(false) expect(custom_field.errors.full_messages.first).to eq( I18n.t("wizard.custom_field.error.unsupported_serializers", - class: "category", - serializers: "category, site_category" + class: "post", + serializers: "post_revision" ) ) expect( @@ -196,6 +192,50 @@ describe CustomWizard::CustomField do ).exists? ).to eq(false) end + + it "does not save pro field types without a pro subscription" do + pro_field_json = custom_field_pro_json['custom_fields'].first + custom_field = CustomWizard::CustomField.new(nil, pro_field_json) + + expect(custom_field.save).to eq(false) + expect(custom_field.valid?).to eq(false) + expect(custom_field.errors.full_messages.first).to eq( + I18n.t("wizard.custom_field.error.pro_type", type: "json") + ) + end + + it "does not save pro field classes without a pro subscription" do + pro_field_json = custom_field_pro_json['custom_fields'].second + custom_field = CustomWizard::CustomField.new(nil, pro_field_json) + + expect(custom_field.save).to eq(false) + expect(custom_field.valid?).to eq(false) + expect(custom_field.errors.full_messages.first).to eq( + I18n.t("wizard.custom_field.error.pro_type", type: "category") + ) + end + + context "with a pro subscription" do + before do + enable_pro + end + + it "saves pro field types" do + pro_field_json = custom_field_pro_json['custom_fields'].first + custom_field = CustomWizard::CustomField.new(nil, pro_field_json) + + expect(custom_field.save).to eq(true) + expect(custom_field.valid?).to eq(true) + end + + it "saves pro field classes" do + pro_field_json = custom_field_pro_json['custom_fields'].second + custom_field = CustomWizard::CustomField.new(nil, pro_field_json) + + expect(custom_field.save).to eq(true) + expect(custom_field.valid?).to eq(true) + end + end end context "lists" do @@ -205,15 +245,15 @@ describe CustomWizard::CustomField do end end - it "lists saved custom field records" do - expect(CustomWizard::CustomField.list.length).to eq(4) + it "saved custom field records" do + expect(CustomWizard::CustomField.list.length).to eq(2) end - it "lists saved custom field records by attribute value" do + it "saved custom field records by attribute value" do expect(CustomWizard::CustomField.list_by(:klass, 'topic').length).to eq(1) end - it "lists saved custom field records by optional values" do + it "saved custom field records by optional values" do field_json = custom_field_json['custom_fields'].first field_json['serializers'] = nil @@ -221,12 +261,12 @@ describe CustomWizard::CustomField do expect(CustomWizard::CustomField.list_by(:serializers, ['post']).length).to eq(0) end - it "lists custom field records added by other plugins " do - expect(CustomWizard::CustomField.external_list.length).to eq(11) + it "custom field records added by other plugins " do + expect(CustomWizard::CustomField.external_list.length).to be > 10 end - it "lists all custom field records" do - expect(CustomWizard::CustomField.full_list.length).to eq(15) + it "all custom field records" do + expect(CustomWizard::CustomField.full_list.length).to be > 12 end end diff --git a/spec/components/custom_wizard/field_spec.rb b/spec/components/custom_wizard/field_spec.rb index 871c42cd..0fcf9fc2 100644 --- a/spec/components/custom_wizard/field_spec.rb +++ b/spec/components/custom_wizard/field_spec.rb @@ -2,11 +2,7 @@ require_relative '../../plugin_helper' describe CustomWizard::Field 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 + let(:field_hash) { get_wizard_fixture("field/field") } before do CustomWizard::Field.register( diff --git a/spec/components/custom_wizard/mapper_spec.rb b/spec/components/custom_wizard/mapper_spec.rb index ed66d7c1..b210c588 100644 --- a/spec/components/custom_wizard/mapper_spec.rb +++ b/spec/components/custom_wizard/mapper_spec.rb @@ -31,16 +31,8 @@ describe CustomWizard::Mapper do ] ) } - 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) - } + let(:inputs) { get_wizard_fixture("mapper/inputs") } + let(:data) { get_wizard_fixture("mapper/data") } let(:template_params) { { "step_1_field_1" => "Hello" @@ -352,7 +344,7 @@ describe CustomWizard::Mapper do expect(result).to eq(template_params["step_1_field_1"]) end - it "treats replaced values as string literals" do + it "requires a pro subscription" do template = '{{ "w{step_1_field_1}" | size }}' mapper = create_template_mapper(template_params, user1) result = mapper.interpolate( @@ -362,60 +354,17 @@ describe CustomWizard::Mapper do wizard: true, value: true ) - expect(result).to eq(template_params["step_1_field_1"].size.to_s) + expect(result).to eq("{{ \"#{template_params["step_1_field_1"]}\" | size }}") end - it "allows the wizard values to be used inside conditionals" do - template = <<-LIQUID - {%- if "w{step_1_field_1}" contains "ello" -%} - Correct - {%- else -%} - Incorrect - {%-endif-%} - LIQUID - mapper = create_template_mapper(template_params, user1) - result = mapper.interpolate( - template.dup, - template: true, - user: true, - wizard: true, - value: true - ) - expect(result).to eq("Correct") - end + context "with a pro subscription" do + before do + enable_pro + end - it "can access data passed to render method as variable" do - template = "{{step_1_field_1.size}}" - mapper = create_template_mapper(template_params, user1) - result = mapper.interpolate( - template.dup, - template: true, - user: true, - wizard: true, - value: true - ) - expect(result).to eq(template_params["step_1_field_1"].size.to_s) - end - - it "doesn't parse the template when template param is false" do - template = <<-LIQUID.strip - {{ "w{step_1_field_1}" | size}} - LIQUID - mapper = create_template_mapper(template_params, user1) - result = mapper.interpolate( - template.dup, - template: false, - ) - expect(result).to eq(template) - end - - context "custom filter: 'first_non_empty'" do - it "gives first non empty element from list" do - template = <<-LIQUID.strip - {%- assign entry = "" | first_non_empty: step_1_field_1, step_1_field_2, step_1_field_3 -%} - {{ entry }} - LIQUID - mapper = create_template_mapper(template_params_non_empty, user1) + it "treats replaced values as string literals" do + template = '{{ "w{step_1_field_1}" | size }}' + mapper = create_template_mapper(template_params, user1) result = mapper.interpolate( template.dup, template: true, @@ -423,15 +372,18 @@ describe CustomWizard::Mapper do wizard: true, value: true ) - expect(result).to eq(template_params_non_empty["step_1_field_3"]) + expect(result).to eq(template_params["step_1_field_1"].size.to_s) end - it "gives first non empty element from list when multiple non empty values present" do - template = <<-LIQUID.strip - {%- assign entry = "" | first_non_empty: step_1_field_1, step_1_field_2, step_1_field_3 -%} - {{ entry }} + it "allows the wizard values to be used inside conditionals" do + template = <<-LIQUID + {%- if "w{step_1_field_1}" contains "ello" -%} + Correct + {%- else -%} + Incorrect + {%-endif-%} LIQUID - mapper = create_template_mapper(template_params_multiple_non_empty, user1) + mapper = create_template_mapper(template_params, user1) result = mapper.interpolate( template.dup, template: true, @@ -439,25 +391,84 @@ describe CustomWizard::Mapper do wizard: true, value: true ) - expect(result).to eq(template_params_multiple_non_empty["step_1_field_2"]) + expect(result).to eq("Correct") end - it "gives empty if all elements are empty" do + it "can access data passed to render method as variable" do + template = "{{step_1_field_1.size}}" + mapper = create_template_mapper(template_params, user1) + result = mapper.interpolate( + template.dup, + template: true, + user: true, + wizard: true, + value: true + ) + expect(result).to eq(template_params["step_1_field_1"].size.to_s) + end + + it "doesn't parse the template when template param is false" do template = <<-LIQUID.strip - {%- assign entry = "" | first_non_empty: step_1_field_1, step_1_field_2, step_1_field_3 -%} - {%- if entry -%} + {{ "w{step_1_field_1}" | size}} + LIQUID + mapper = create_template_mapper(template_params, user1) + result = mapper.interpolate( + template.dup, + template: false, + ) + expect(result).to eq(template) + end + + context "custom filter: 'first_non_empty'" do + it "gives first non empty element from list" do + template = <<-LIQUID.strip + {%- assign entry = "" | first_non_empty: step_1_field_1, step_1_field_2, step_1_field_3 -%} {{ entry }} - {%- endif -%} - LIQUID - mapper = create_template_mapper(template_params_empty, user1) - result = mapper.interpolate( - template.dup, - template: true, - user: true, - wizard: true, - value: true - ) - expect(result).to eq("") + LIQUID + mapper = create_template_mapper(template_params_non_empty, user1) + result = mapper.interpolate( + template.dup, + template: true, + user: true, + wizard: true, + value: true + ) + expect(result).to eq(template_params_non_empty["step_1_field_3"]) + end + + it "gives first non empty element from list when multiple non empty values present" do + template = <<-LIQUID.strip + {%- assign entry = "" | first_non_empty: step_1_field_1, step_1_field_2, step_1_field_3 -%} + {{ entry }} + LIQUID + mapper = create_template_mapper(template_params_multiple_non_empty, user1) + result = mapper.interpolate( + template.dup, + template: true, + user: true, + wizard: true, + value: true + ) + expect(result).to eq(template_params_multiple_non_empty["step_1_field_2"]) + end + + it "gives empty if all elements are empty" do + template = <<-LIQUID.strip + {%- assign entry = "" | first_non_empty: step_1_field_1, step_1_field_2, step_1_field_3 -%} + {%- if entry -%} + {{ entry }} + {%- endif -%} + LIQUID + mapper = create_template_mapper(template_params_empty, user1) + result = mapper.interpolate( + template.dup, + template: true, + user: true, + wizard: true, + value: true + ) + expect(result).to eq("") + end end end end diff --git a/spec/components/custom_wizard/pro_spec.rb b/spec/components/custom_wizard/pro_spec.rb new file mode 100644 index 00000000..6c83ae3b --- /dev/null +++ b/spec/components/custom_wizard/pro_spec.rb @@ -0,0 +1,125 @@ +# frozen_string_literal: true + +require_relative '../../plugin_helper' + +describe CustomWizard::Pro do + fab!(:user) { Fabricate(:user) } + + it "initializes pro authentication and subscription" do + pro = described_class.new + expect(pro.authentication.class).to eq(CustomWizard::ProAuthentication) + expect(pro.subscription.class).to eq(CustomWizard::ProSubscription) + end + + it "returns authorized and subscribed states" do + pro = described_class.new + expect(pro.authorized?).to eq(false) + expect(pro.subscribed?).to eq(false) + end + + context "subscription" do + before do + @pro = described_class.new + end + + it "updates valid subscriptions" do + stub_subscription_request(200, valid_subscription) + expect(@pro.update_subscription).to eq(true) + expect(@pro.subscribed?).to eq(true) + end + + it "handles invalid subscriptions" do + stub_subscription_request(200, invalid_subscription) + expect(@pro.update_subscription).to eq(false) + expect(@pro.subscribed?).to eq(false) + end + + it "handles subscription http errors" do + stub_subscription_request(404, {}) + expect(@pro.update_subscription).to eq(false) + expect(@pro.subscribed?).to eq(false) + end + + it "destroys subscriptions" do + stub_subscription_request(200, valid_subscription) + expect(@pro.update_subscription).to eq(true) + expect(@pro.destroy_subscription).to eq(true) + expect(@pro.subscribed?).to eq(false) + end + + it "has class aliases" do + authenticate_pro + stub_subscription_request(200, valid_subscription) + expect(described_class.update_subscription).to eq(true) + expect(described_class.subscribed?).to eq(true) + end + end + + context "authentication" do + before do + @pro = described_class.new + user.update!(admin: true) + end + + it "generates a valid authentication request url" do + request_id = SecureRandom.hex(32) + uri = URI(@pro.authentication_url(user.id, request_id)) + expect(uri.host).to eq(@pro.server) + + parsed_query = Rack::Utils.parse_query uri.query + expect(parsed_query['public_key'].present?).to eq(true) + expect(parsed_query['nonce'].present?).to eq(true) + expect(parsed_query['client_id'].present?).to eq(true) + expect(parsed_query['auth_redirect'].present?).to eq(true) + expect(parsed_query['application_name']).to eq(SiteSetting.title) + expect(parsed_query['scopes']).to eq(@pro.scope) + end + + def generate_payload(request_id, user_id) + uri = URI(@pro.authentication_url(user_id, request_id)) + keys = @pro.authentication.get_keys(request_id) + raw_payload = { + key: "12345", + nonce: keys.nonce, + push: false, + api: UserApiKeysController::AUTH_API_VERSION + }.to_json + public_key = OpenSSL::PKey::RSA.new(keys.pem) + Base64.encode64(public_key.public_encrypt(raw_payload)) + end + + it "handles authentication response if request and response is valid" do + request_id = SecureRandom.hex(32) + payload = generate_payload(request_id, user.id) + + expect(@pro.authentication_response(request_id, payload)).to eq(true) + expect(@pro.authorized?).to eq(true) + end + + it "discards authentication response if user who made request as not an admin" do + user.update!(admin: false) + + request_id = SecureRandom.hex(32) + payload = generate_payload(request_id, user.id) + + expect(@pro.authentication_response(request_id, payload)).to eq(false) + expect(@pro.authorized?).to eq(false) + end + + it "discards authentication response if request_id is invalid" do + payload = generate_payload(SecureRandom.hex(32), user.id) + + expect(@pro.authentication_response(SecureRandom.hex(32), payload)).to eq(false) + expect(@pro.authorized?).to eq(false) + end + + it "destroys authentication" do + request_id = SecureRandom.hex(32) + payload = generate_payload(request_id, user.id) + @pro.authentication_response(request_id, payload) + + expect(@pro.destroy_authentication).to eq(true) + expect(@pro.authorized?).to eq(false) + end + end +end \ No newline at end of file diff --git a/spec/components/custom_wizard/step_spec.rb b/spec/components/custom_wizard/step_spec.rb index bf4613a4..9ad02176 100644 --- a/spec/components/custom_wizard/step_spec.rb +++ b/spec/components/custom_wizard/step_spec.rb @@ -2,21 +2,8 @@ require_relative '../../plugin_helper' describe CustomWizard::Step 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 - - let(:field_hash) do - JSON.parse( - File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/field/field.json" - ).read - ).with_indifferent_access - end + let(:step_hash) { get_wizard_fixture("step/step") } + let(:field_hash) { get_wizard_fixture("field/field") } before do @step = CustomWizard::Step.new(step_hash[:id]) diff --git a/spec/components/custom_wizard/submission_spec.rb b/spec/components/custom_wizard/submission_spec.rb index b85af243..a838820d 100644 --- a/spec/components/custom_wizard/submission_spec.rb +++ b/spec/components/custom_wizard/submission_spec.rb @@ -4,12 +4,7 @@ require_relative '../../plugin_helper' describe CustomWizard::Submission do fab!(:user) { Fabricate(:user) } fab!(:user2) { Fabricate(:user) } - - let(:template_json) { - JSON.parse(File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json" - ).read) - } + let(:template_json) { get_wizard_fixture("wizard") } before do CustomWizard::Template.save(template_json, skip_jobs: true) diff --git a/spec/components/custom_wizard/template_spec.rb b/spec/components/custom_wizard/template_spec.rb index 0e3dbdbe..fca7f91e 100644 --- a/spec/components/custom_wizard/template_spec.rb +++ b/spec/components/custom_wizard/template_spec.rb @@ -3,17 +3,8 @@ require_relative '../../plugin_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(:template_json) { get_wizard_fixture("wizard") } + let(:permitted_json) { get_wizard_fixture("wizard/permitted") } before do CustomWizard::Template.save(template_json, skip_jobs: true) diff --git a/spec/components/custom_wizard/template_validator_spec.rb b/spec/components/custom_wizard/template_validator_spec.rb index c8ce915a..7a84660c 100644 --- a/spec/components/custom_wizard/template_validator_spec.rb +++ b/spec/components/custom_wizard/template_validator_spec.rb @@ -3,12 +3,9 @@ require_relative '../../plugin_helper' describe CustomWizard::TemplateValidator 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(:template) { get_wizard_fixture("wizard") } + let(:create_category) { get_wizard_fixture("actions/create_category") } + let(:user_condition) { get_wizard_fixture("condition/user_condition") } it "validates valid templates" do expect( @@ -45,4 +42,52 @@ describe CustomWizard::TemplateValidator do CustomWizard::TemplateValidator.new(template).perform ).to eq(false) end + + it "invalidates pro step attributes without a pro subscription" do + template[:steps][0][:condition] = user_condition['condition'] + expect( + CustomWizard::TemplateValidator.new(template).perform + ).to eq(false) + end + + it "invalidates pro field attributes without a pro subscription" do + template[:steps][0][:fields][0][:condition] = user_condition['condition'] + expect( + CustomWizard::TemplateValidator.new(template).perform + ).to eq(false) + end + + it "invalidates pro actions without a pro subscription" do + template[:actions] << create_category + expect( + CustomWizard::TemplateValidator.new(template).perform + ).to eq(false) + end + + context "with pro subscription" do + before do + enable_pro + end + + it "validates pro step attributes" do + template[:steps][0][:condition] = user_condition['condition'] + expect( + CustomWizard::TemplateValidator.new(template).perform + ).to eq(true) + end + + it "validates pro field attributes" do + template[:steps][0][:fields][0][:condition] = user_condition['condition'] + expect( + CustomWizard::TemplateValidator.new(template).perform + ).to eq(true) + end + + it "validates pro actions" do + template[:actions] << create_category + expect( + CustomWizard::TemplateValidator.new(template).perform + ).to eq(true) + end + end end diff --git a/spec/components/custom_wizard/update_validator_spec.rb b/spec/components/custom_wizard/update_validator_spec.rb index e976e1ff..c79a5b0b 100644 --- a/spec/components/custom_wizard/update_validator_spec.rb +++ b/spec/components/custom_wizard/update_validator_spec.rb @@ -3,12 +3,7 @@ require_relative '../../plugin_helper' describe CustomWizard::UpdateValidator 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(:template) { get_wizard_fixture("wizard") } before do CustomWizard::Template.save(template, skip_jobs: true) diff --git a/spec/components/custom_wizard/wizard_spec.rb b/spec/components/custom_wizard/wizard_spec.rb index 67905f5a..9cccff97 100644 --- a/spec/components/custom_wizard/wizard_spec.rb +++ b/spec/components/custom_wizard/wizard_spec.rb @@ -6,22 +6,8 @@ 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(:permitted_json) { - JSON.parse( - File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/permitted.json" - ).read - ) - } + let(:template_json) { get_wizard_fixture("wizard") } + let(:permitted_json) { get_wizard_fixture("wizard/permitted") } before do Group.refresh_automatic_group!(:trust_level_3) diff --git a/spec/extensions/custom_field_extensions_spec.rb b/spec/extensions/custom_field_extensions_spec.rb index f0ce32f5..bf1b3ff2 100644 --- a/spec/extensions/custom_field_extensions_spec.rb +++ b/spec/extensions/custom_field_extensions_spec.rb @@ -9,11 +9,8 @@ describe "custom field extensions" do fab!(:group) { Fabricate(:group) } fab!(:user) { Fabricate(:user) } - let(:custom_field_json) { - JSON.parse(File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/custom_field/custom_fields.json" - ).read) - } + let(:custom_field_json) { get_wizard_fixture("custom_field/custom_fields") } + let(:pro_custom_field_json) { get_wizard_fixture("custom_field/pro_custom_fields") } before do custom_field_json['custom_fields'].each do |field_json| @@ -75,43 +72,54 @@ describe "custom field extensions" do end end - context "category" do - it "registers category custom fields" do - category - expect(Category.get_custom_field_type("category_field_1")).to eq(:json) + context "pro custom fields" do + before do + enable_pro + + pro_custom_field_json['custom_fields'].each do |field_json| + custom_field = CustomWizard::CustomField.new(nil, field_json) + custom_field.save + end end - it "adds category custom fields to the basic category serializer" do - category.custom_fields["category_field_1"] = { a: 1, b: 2 }.to_json - category.save_custom_fields(true) + context "category" do + it "registers" do + category + expect(Category.get_custom_field_type("category_field_1")).to eq(:json) + end - serializer = BasicCategorySerializer.new( - category, - scope: Guardian.new(user), - root: false - ).as_json + it "adds custom fields to the basic category serializer" do + category.custom_fields["category_field_1"] = { a: 1, b: 2 }.to_json + category.save_custom_fields(true) - expect(serializer[:category_field_1]).to eq({ a: 1, b: 2 }.to_json) - end - end + serializer = BasicCategorySerializer.new( + category, + scope: Guardian.new(user), + root: false + ).as_json - context "group" do - it "registers group custom fields" do - group - expect(Group.get_custom_field_type("group_field_1")).to eq(:string) + expect(serializer[:category_field_1]).to eq({ a: 1, b: 2 }.to_json) + end end - it "adds group custom fields to the basic group serializer" do - group.custom_fields["group_field_1"] = "Hello" - group.save_custom_fields(true) + context "group" do + it "registers" do + group + expect(Group.get_custom_field_type("group_field_1")).to eq(:string) + end - serializer = BasicGroupSerializer.new( - group, - scope: Guardian.new(user), - root: false - ).as_json + it "adds custom fields to the basic group serializer" do + group.custom_fields["group_field_1"] = "Hello" + group.save_custom_fields(true) - expect(serializer[:group_field_1]).to eq("Hello") + serializer = BasicGroupSerializer.new( + group, + scope: Guardian.new(user), + root: false + ).as_json + + expect(serializer[:group_field_1]).to eq("Hello") + end end end end diff --git a/spec/extensions/extra_locales_controller_spec.rb b/spec/extensions/extra_locales_controller_spec.rb index a71e39c4..bb451b7c 100644 --- a/spec/extensions/extra_locales_controller_spec.rb +++ b/spec/extensions/extra_locales_controller_spec.rb @@ -4,18 +4,8 @@ require_relative '../plugin_helper' describe ExtraLocalesControllerCustomWizard, type: :request do let(:new_user) { Fabricate(:user, trust_level: TrustLevel[0]) } let(:staff_user) { Fabricate(:moderator) } - - let(:template) { - JSON.parse(File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json" - ).read) - } - - let(:permitted) { - JSON.parse(File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/permitted.json" - ).read) - } + let(:template) { get_wizard_fixture("wizard") } + let(:permitted) { get_wizard_fixture("wizard/permitted") } before do CustomWizard::Template.save(template, skip_jobs: true) diff --git a/spec/extensions/invites_controller_spec.rb b/spec/extensions/invites_controller_spec.rb index 47c4ca84..93fdd9d7 100644 --- a/spec/extensions/invites_controller_spec.rb +++ b/spec/extensions/invites_controller_spec.rb @@ -4,12 +4,7 @@ require_relative '../plugin_helper' describe InvitesControllerCustomWizard, type: :request do fab!(:topic) { Fabricate(:topic) } let(:invite) { Invite.generate(topic.user, email: "angus@mcleod.org", topic: topic) } - - let(:template) do - JSON.parse(File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json" - ).read) - end + let(:template) { get_wizard_fixture("wizard") } before do @controller = InvitesController.new diff --git a/spec/extensions/users_controller_spec.rb b/spec/extensions/users_controller_spec.rb index f4ba8e51..e4cd972f 100644 --- a/spec/extensions/users_controller_spec.rb +++ b/spec/extensions/users_controller_spec.rb @@ -2,11 +2,7 @@ require_relative '../plugin_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 + let(:template) { get_wizard_fixture("wizard") } before do @controller = UsersController.new diff --git a/spec/fixtures/actions/add_to_group.json b/spec/fixtures/actions/add_to_group.json new file mode 100644 index 00000000..2a5af1c3 --- /dev/null +++ b/spec/fixtures/actions/add_to_group.json @@ -0,0 +1,13 @@ +{ + "id": "action_6", + "run_after": "step_1", + "type": "add_to_group", + "group": [ + { + "type": "assignment", + "output": "action_9", + "output_type": "wizard_action", + "output_connector": "set" + } + ] +} \ No newline at end of file diff --git a/spec/fixtures/actions/create_category.json b/spec/fixtures/actions/create_category.json new file mode 100644 index 00000000..c5f3d5af --- /dev/null +++ b/spec/fixtures/actions/create_category.json @@ -0,0 +1,51 @@ +{ + "id": "action_8", + "run_after": "step_1", + "type": "create_category", + "custom_fields": [ + { + "type": "association", + "pairs": [ + { + "index": 0, + "key": "category_custom_field", + "key_type": "text", + "value": "CC Val", + "value_type": "text", + "connector": "association" + } + ] + } + ], + "name": [ + { + "type": "assignment", + "output": "step_1_field_1", + "output_type": "wizard_field", + "output_connector": "set" + } + ], + "slug": [ + { + "type": "assignment", + "output": "step_1_field_1", + "output_type": "wizard_field", + "output_connector": "set" + } + ], + "permissions": [ + { + "type": "association", + "pairs": [ + { + "index": 0, + "key": "action_9", + "key_type": "wizard_action", + "value": "2", + "value_type": "text", + "connector": "association" + } + ] + } + ] +} \ No newline at end of file diff --git a/spec/fixtures/actions/create_group.json b/spec/fixtures/actions/create_group.json new file mode 100644 index 00000000..e2e52ef2 --- /dev/null +++ b/spec/fixtures/actions/create_group.json @@ -0,0 +1,104 @@ +{ + "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" + } + ] +} \ No newline at end of file diff --git a/spec/fixtures/actions/send_message.json b/spec/fixtures/actions/send_message.json new file mode 100644 index 00000000..ddc9bf10 --- /dev/null +++ b/spec/fixtures/actions/send_message.json @@ -0,0 +1,25 @@ +{ + "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" + ] + } + ] +} \ No newline at end of file diff --git a/spec/fixtures/actions/send_message_multi.json b/spec/fixtures/actions/send_message_multi.json new file mode 100644 index 00000000..8ab0fdb7 --- /dev/null +++ b/spec/fixtures/actions/send_message_multi.json @@ -0,0 +1,28 @@ +{ + "id": "action_11", + "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": "Multiple Recipients title", + "output_type": "text", + "output_connector": "set" + } + ], + "recipient": [ + { + "type": "assignment", + "output_type": "user", + "output_connector": "set", + "output": [ + "angus1", + "faiz", + "cool_group", + "cool_group_1" + ] + } + ] +} \ No newline at end of file diff --git a/spec/fixtures/custom_field/custom_fields.json b/spec/fixtures/custom_field/custom_fields.json index 0e7741ce..c9b98476 100644 --- a/spec/fixtures/custom_field/custom_fields.json +++ b/spec/fixtures/custom_field/custom_fields.json @@ -16,22 +16,6 @@ "serializers": [ "post" ] - }, - { - "klass": "category", - "name": "category_field_1", - "type": "json", - "serializers": [ - "basic_category" - ] - }, - { - "klass": "group", - "name": "group_field_1", - "type": "string", - "serializers": [ - "basic_group" - ] } ] } \ No newline at end of file diff --git a/spec/fixtures/custom_field/pro_custom_fields.json b/spec/fixtures/custom_field/pro_custom_fields.json new file mode 100644 index 00000000..b7060bdf --- /dev/null +++ b/spec/fixtures/custom_field/pro_custom_fields.json @@ -0,0 +1,28 @@ +{ + "custom_fields": [ + { + "klass": "topic", + "name": "topic_field_2", + "type": "json", + "serializers": [ + "topic_view" + ] + }, + { + "klass": "category", + "name": "category_field_1", + "type": "json", + "serializers": [ + "basic_category" + ] + }, + { + "klass": "group", + "name": "group_field_1", + "type": "string", + "serializers": [ + "basic_group" + ] + } + ] +} \ No newline at end of file diff --git a/spec/fixtures/wizard.json b/spec/fixtures/wizard.json index a505c0d3..1560acef 100644 --- a/spec/fixtures/wizard.json +++ b/spec/fixtures/wizard.json @@ -163,197 +163,6 @@ } ], "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": "action_6", - "run_after": "step_1", - "type": "add_to_group", - "group": [ - { - "type": "assignment", - "output": "action_9", - "output_type": "wizard_action", - "output_connector": "set" - } - ] - }, - { - "id": "action_8", - "run_after": "step_1", - "type": "create_category", - "custom_fields": [ - { - "type": "association", - "pairs": [ - { - "index": 0, - "key": "category_custom_field", - "key_type": "text", - "value": "CC Val", - "value_type": "text", - "connector": "association" - } - ] - } - ], - "name": [ - { - "type": "assignment", - "output": "step_1_field_1", - "output_type": "wizard_field", - "output_connector": "set" - } - ], - "slug": [ - { - "type": "assignment", - "output": "step_1_field_1", - "output_type": "wizard_field", - "output_connector": "set" - } - ], - "permissions": [ - { - "type": "association", - "pairs": [ - { - "index": 0, - "key": "action_9", - "key_type": "wizard_action", - "value": "2", - "value_type": "text", - "connector": "association" - } - ] - } - ] - }, - { - "id": "action_5", - "run_after": "step_1", - "type": "watch_categories", - "notification_level": "tracking", - "wizard_user": true, - "categories": [ - { - "type": "assignment", - "output": "action_8", - "output_type": "wizard_action", - "output_connector": "set" - } - ], - "mute_remainder": [ - { - "type": "assignment", - "output": "true", - "output_type": "text", - "output_connector": "set" - } - ] - }, { "id": "action_1", "run_after": "step_3", @@ -442,6 +251,29 @@ } ] }, + { + "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_4", "run_after": "step_2", @@ -462,59 +294,6 @@ } ] }, - { - "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_11", - "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": "Multiple Recipients title", - "output_type": "text", - "output_connector": "set" - } - ], - "recipient": [ - { - "type": "assignment", - "output_type": "user", - "output_connector": "set", - "output": [ - "angus1", - "faiz", - "cool_group", - "cool_group_1" - ] - } - ] - }, { "id": "action_3", "run_after": "step_2", @@ -529,24 +308,6 @@ "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", diff --git a/spec/jobs/set_after_time_wizard_spec.rb b/spec/jobs/set_after_time_wizard_spec.rb index 35576f01..93e46c8b 100644 --- a/spec/jobs/set_after_time_wizard_spec.rb +++ b/spec/jobs/set_after_time_wizard_spec.rb @@ -7,11 +7,7 @@ describe Jobs::SetAfterTimeWizard do 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(:template) { get_wizard_fixture("wizard") } it "sets wizard redirect for all users " do after_time_template = template.dup diff --git a/spec/jobs/update_pro_subscription_spec.rb b/spec/jobs/update_pro_subscription_spec.rb new file mode 100644 index 00000000..0aae9668 --- /dev/null +++ b/spec/jobs/update_pro_subscription_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require_relative '../plugin_helper' + +describe CustomWizard::UpdateProSubscription do + it "updates the pro subscription" do + stub_subscription_request(200, valid_subscription) + described_class.new.execute + expect(CustomWizard::Pro.subscribed?).to eq(true) + end +end diff --git a/spec/plugin_helper.rb b/spec/plugin_helper.rb index 9e4bbbbe..4aa34029 100644 --- a/spec/plugin_helper.rb +++ b/spec/plugin_helper.rb @@ -15,3 +15,44 @@ require 'oj' Oj.default_options = Oj.default_options.merge(cache_str: -1) require 'rails_helper' + +def get_wizard_fixture(path) + JSON.parse( + File.open( + "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/#{path}.json" + ).read + ).with_indifferent_access +end + +def authenticate_pro + CustomWizard::ProAuthentication.any_instance.stubs(:active?).returns(true) +end + +def enable_pro + CustomWizard::Pro.any_instance.stubs(:subscribed?).returns(true) +end + +def disable_pro + CustomWizard::Pro.any_instance.stubs(:subscribed?).returns(false) +end + +def valid_subscription + { + product_id: "prod_CBTNpi3fqWWkq0", + price_id: "price_id", + price_nickname: "business" + } +end + +def invalid_subscription + { + product_id: "prod_CBTNpi3fqWWkq0", + price_id: "price_id" + } +end + +def stub_subscription_request(status, subscription) + authenticate_pro + pro = CustomWizard::Pro.new + stub_request(:get, "https://#{pro.server}/subscription-server/user-subscriptions/#{pro.subscription_type}/#{pro.client_name}").to_return(status: status, body: { subscriptions: [subscription] }.to_json) +end diff --git a/spec/requests/custom_wizard/admin/custom_fields_controller_spec.rb b/spec/requests/custom_wizard/admin/custom_fields_controller_spec.rb index 8c1a8550..d2e086d2 100644 --- a/spec/requests/custom_wizard/admin/custom_fields_controller_spec.rb +++ b/spec/requests/custom_wizard/admin/custom_fields_controller_spec.rb @@ -3,12 +3,7 @@ require_relative '../../../plugin_helper' describe CustomWizard::AdminCustomFieldsController do fab!(:admin_user) { Fabricate(:user, admin: true) } - - let(:custom_field_json) { - JSON.parse(File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/custom_field/custom_fields.json" - ).read) - } + let(:custom_field_json) { get_wizard_fixture("custom_field/custom_fields") } before do custom_field_json['custom_fields'].each do |field_json| @@ -19,7 +14,7 @@ describe CustomWizard::AdminCustomFieldsController do it "returns the full list of custom fields" do get "/admin/wizards/custom-fields.json" - expect(response.parsed_body.length).to eq(15) + expect(response.parsed_body["custom_fields"].length).to be > 12 end it "saves custom fields" do diff --git a/spec/requests/custom_wizard/admin/manager_controller_spec.rb b/spec/requests/custom_wizard/admin/manager_controller_spec.rb index 87c980f2..6218ea7e 100644 --- a/spec/requests/custom_wizard/admin/manager_controller_spec.rb +++ b/spec/requests/custom_wizard/admin/manager_controller_spec.rb @@ -3,12 +3,7 @@ require_relative '../../../plugin_helper' describe CustomWizard::AdminManagerController 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) - } + let(:template) { get_wizard_fixture("wizard") } before do sign_in(admin_user) diff --git a/spec/requests/custom_wizard/admin/pro_controller_spec.rb b/spec/requests/custom_wizard/admin/pro_controller_spec.rb new file mode 100644 index 00000000..049bb88e --- /dev/null +++ b/spec/requests/custom_wizard/admin/pro_controller_spec.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true +require_relative '../../../plugin_helper' + +describe CustomWizard::AdminProController do + fab!(:admin_user) { Fabricate(:user, admin: true) } + + def generate_payload(request_id, user_id) + uri = URI(@pro.authentication_url(user_id, request_id)) + keys = @pro.authentication.get_keys(request_id) + raw_payload = { + key: "12345", + nonce: keys.nonce, + push: false, + api: UserApiKeysController::AUTH_API_VERSION + }.to_json + public_key = OpenSSL::PKey::RSA.new(keys.pem) + Base64.encode64(public_key.public_encrypt(raw_payload)) + end + + before do + @pro = CustomWizard::Pro.new + sign_in(admin_user) + end + + it "#index" do + get "/admin/wizards/pro.json" + expect(response.parsed_body['server']).to eq(@pro.server) + expect(response.parsed_body['authentication'].deep_symbolize_keys).to eq(CustomWizard::ProAuthenticationSerializer.new(@pro.authentication, root: false).as_json) + expect(response.parsed_body['subscription'].deep_symbolize_keys).to eq(CustomWizard::ProSubscriptionSerializer.new(@pro.subscription, root: false).as_json) + end + + it "#authorize" do + get "/admin/wizards/pro/authorize" + expect(response.status).to eq(302) + expect(cookies[:user_api_request_id].present?).to eq(true) + end + + it "#destroy_authentication" do + request_id = SecureRandom.hex(32) + payload = generate_payload(request_id, admin_user.id) + @pro.authentication_response(request_id, payload) + + delete "/admin/wizards/pro/authorize.json" + + expect(response.status).to eq(200) + expect(CustomWizard::Pro.authorized?).to eq(false) + end + + context "subscription" do + before do + stub_subscription_request(200, valid_subscription) + end + + it "handles authentication response and the updates subscription" do + request_id = cookies[:user_api_request_id] = SecureRandom.hex(32) + payload = generate_payload(request_id, admin_user.id) + get "/admin/wizards/pro/authorize/callback", params: { payload: payload } + + expect(response).to redirect_to("/admin/wizards/pro") + expect(CustomWizard::Pro.subscribed?).to eq(true) + end + + it "updates the subscription" do + authenticate_pro + post "/admin/wizards/pro/subscription.json" + + expect(response.status).to eq(200) + expect(CustomWizard::Pro.subscribed?).to eq(true) + end + end +end \ No newline at end of file diff --git a/spec/requests/custom_wizard/admin/submissions_controller_spec.rb b/spec/requests/custom_wizard/admin/submissions_controller_spec.rb index 36296e95..5a79679f 100644 --- a/spec/requests/custom_wizard/admin/submissions_controller_spec.rb +++ b/spec/requests/custom_wizard/admin/submissions_controller_spec.rb @@ -7,12 +7,7 @@ describe CustomWizard::AdminSubmissionsController do 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) - } - + let(:template) { get_wizard_fixture("wizard") } let(:template_2) { temp = template.dup temp["id"] = "super_mega_fun_wizard_2" diff --git a/spec/requests/custom_wizard/admin/wizard_controller_spec.rb b/spec/requests/custom_wizard/admin/wizard_controller_spec.rb index 82aa4fc5..9d7ed18d 100644 --- a/spec/requests/custom_wizard/admin/wizard_controller_spec.rb +++ b/spec/requests/custom_wizard/admin/wizard_controller_spec.rb @@ -5,12 +5,7 @@ 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) - } + let(:template) { get_wizard_fixture("wizard") } before do CustomWizard::Template.save(template, skip_jobs: true) diff --git a/spec/requests/custom_wizard/application_controller_spec.rb b/spec/requests/custom_wizard/application_controller_spec.rb index 0835f246..f92ac7c0 100644 --- a/spec/requests/custom_wizard/application_controller_spec.rb +++ b/spec/requests/custom_wizard/application_controller_spec.rb @@ -2,21 +2,11 @@ require_relative '../../plugin_helper' describe ApplicationController do - fab!(:user) { - Fabricate( - :user, - username: 'angus', - email: "angus@email.com", - trust_level: TrustLevel[3] - ) - } + fab!(:user) { Fabricate(:user, username: 'angus', email: "angus@email.com", trust_level: TrustLevel[3]) } + let(:wizard_template) { get_wizard_fixture("wizard") } before do - CustomWizard::Template.save( - JSON.parse(File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json" - ).read), - skip_jobs: true) + CustomWizard::Template.save(wizard_template, skip_jobs: true) @template = CustomWizard::Template.find('super_mega_fun_wizard') end diff --git a/spec/requests/custom_wizard/custom_field_extensions_spec.rb b/spec/requests/custom_wizard/custom_field_extensions_spec.rb index b991769a..64d7c755 100644 --- a/spec/requests/custom_wizard/custom_field_extensions_spec.rb +++ b/spec/requests/custom_wizard/custom_field_extensions_spec.rb @@ -8,12 +8,8 @@ describe "custom field extensions" do let!(:category) { Fabricate(:category) } let!(:user) { Fabricate(:user) } let!(:group) { Fabricate(:group, users: [user]) } - - let(:custom_field_json) { - JSON.parse(File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/custom_field/custom_fields.json" - ).read) - } + let(:custom_field_json) { get_wizard_fixture("custom_field/custom_fields") } + let(:pro_custom_field_json) { get_wizard_fixture("custom_field/pro_custom_fields") } before do custom_field_json['custom_fields'].each do |field_json| @@ -32,27 +28,6 @@ describe "custom field extensions" do expect(response.parsed_body["topic_field_1"]).to eq(true) end - it "adds category custom fields to the show categories response" do - category.custom_fields["category_field_1"] = { a: 1, b: 2 } - category.save_custom_fields(true) - - get "/c/#{category.id}/show.json" - - expect(response.status).to eq(200) - expect(response.parsed_body["category"]["category_field_1"]).to eq({ a: 1, b: 2 }.as_json) - end - - it "adds group custom fields to the show group response" do - group.custom_fields["group_field_1"] = "Group cf entry" - group.save_custom_fields(true) - - sign_in(user) - get "/groups/#{group.name}.json" - - expect(response.status).to eq(200) - expect(response.parsed_body['group']['group_field_1']).to eq("Group cf entry") - end - it "adds post custom fields to the show post response" do post.custom_fields["post_field_1"] = 7 post.save_custom_fields(true) @@ -63,32 +38,64 @@ describe "custom field extensions" do expect(response.parsed_body['post_field_1']).to eq(7) end - context "preloaded" do - it "preloads category custom fields on site categories" do - Site.preloaded_category_custom_fields << "other_field" + context "with a pro subscription" do + before do + enable_pro + pro_custom_field_json['custom_fields'].each do |field_json| + custom_field = CustomWizard::CustomField.new(nil, field_json) + custom_field.save + end + end + + it "adds category custom fields to the show categories response" do category.custom_fields["category_field_1"] = { a: 1, b: 2 } category.save_custom_fields(true) - get "/site.json" - expect(response.status).to eq(200) + get "/c/#{category.id}/show.json" - site_category = response.parsed_body['categories'].select { |c| c['id'] == category.id }.first - expect(site_category["category_field_1"]).to eq({ a: 1, b: 2 }.as_json) + expect(response.status).to eq(200) + expect(response.parsed_body["category"]["category_field_1"]).to eq({ a: 1, b: 2 }.as_json) end - it "preloads group custom fields on group index" do - Group.preloaded_custom_field_names << "other_field" - - group = Fabricate(:group) + it "adds group custom fields to the show group response" do group.custom_fields["group_field_1"] = "Group cf entry" group.save_custom_fields(true) - get "/groups.json" - expect(response.status).to eq(200) + sign_in(user) + get "/groups/#{group.name}.json" - group = response.parsed_body['groups'].select { |g| g['id'] == group.id }.first - expect(group['group_field_1']).to eq("Group cf entry") + expect(response.status).to eq(200) + expect(response.parsed_body['group']['group_field_1']).to eq("Group cf entry") + end + + context "preloaded" do + it "preloads category custom fields on site categories" do + Site.preloaded_category_custom_fields << "other_field" + + category.custom_fields["category_field_1"] = { a: 1, b: 2 } + category.save_custom_fields(true) + + get "/site.json" + expect(response.status).to eq(200) + + site_category = response.parsed_body['categories'].select { |c| c['id'] == category.id }.first + expect(site_category["category_field_1"]).to eq({ a: 1, b: 2 }.as_json) + end + + it "preloads group custom fields on group index" do + Group.preloaded_custom_field_names << "other_field" + + group = Fabricate(:group) + group.custom_fields["group_field_1"] = "Group cf entry" + group.save_custom_fields(true) + + get "/groups.json" + expect(response.status).to eq(200) + + group = response.parsed_body['groups'].select { |g| g['id'] == group.id }.first + expect(group['group_field_1']).to eq("Group cf entry") + end end end end diff --git a/spec/requests/custom_wizard/steps_controller_spec.rb b/spec/requests/custom_wizard/steps_controller_spec.rb index 5da75d8d..3564780f 100644 --- a/spec/requests/custom_wizard/steps_controller_spec.rb +++ b/spec/requests/custom_wizard/steps_controller_spec.rb @@ -2,55 +2,12 @@ require_relative '../../plugin_helper' describe CustomWizard::StepsController do - fab!(:user) { - Fabricate( - :user, - username: 'angus', - email: "angus@email.com", - trust_level: TrustLevel[3] - ) - } - - fab!(:user2) { - Fabricate( - :user, - username: 'bob', - email: "bob@email.com", - trust_level: TrustLevel[2] - ) - } - - let(:wizard_template) { - JSON.parse( - File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json" - ).read - ) - } - - let(:wizard_field_condition_template) { - JSON.parse( - File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/condition/wizard_field_condition.json" - ).read - ) - } - - let(:user_condition_template) { - JSON.parse( - File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/condition/user_condition.json" - ).read - ) - } - - let(:permitted_json) { - JSON.parse( - File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/permitted.json" - ).read - ) - } + fab!(:user) { Fabricate(:user, username: 'angus', email: "angus@email.com", trust_level: TrustLevel[3]) } + fab!(:user2) { Fabricate(:user, username: 'bob', email: "bob@email.com", trust_level: TrustLevel[2]) } + let(:wizard_template) { get_wizard_fixture("wizard") } + let(:wizard_field_condition_template) { get_wizard_fixture("condition/wizard_field_condition") } + let(:user_condition_template) { get_wizard_fixture("condition/user_condition") } + let(:permitted_json) { get_wizard_fixture("wizard/permitted") } before do CustomWizard::Template.save(wizard_template, skip_jobs: true) @@ -90,17 +47,6 @@ describe CustomWizard::StepsController do put '/w/super-mega-fun-wizard/steps/step_10.json' expect(response.status).to eq(400) end - - it "when user cant see the step due to conditions" do - sign_in(user2) - - new_wizard_template = wizard_template.dup - new_wizard_template['steps'][0]['condition'] = user_condition_template['condition'] - CustomWizard::Template.save(new_wizard_template, skip_jobs: true) - - put '/w/super-mega-fun-wizard/steps/step_1.json' - expect(response.status).to eq(403) - end end it "works if the step has no fields" do @@ -123,64 +69,40 @@ describe CustomWizard::StepsController do expect(response.parsed_body['wizard']['start']).to eq("step_2") end - it "returns an updated wizard when condition doesnt pass" do - new_template = wizard_template.dup - new_template['steps'][1]['condition'] = wizard_field_condition_template['condition'] - CustomWizard::Template.save(new_template, skip_jobs: true) - - put '/w/super-mega-fun-wizard/steps/step_1.json', params: { - fields: { - step_1_field_1: "Condition wont pass" - } - } - expect(response.status).to eq(200) - expect(response.parsed_body['wizard']['start']).to eq("step_3") - end - it "runs completion actions if user has completed wizard" do new_template = wizard_template.dup ## route_to action new_template['actions'].last['run_after'] = 'wizard_completion' - new_template['steps'][1]['condition'] = wizard_field_condition_template['condition'] - new_template['steps'][2]['condition'] = wizard_field_condition_template['condition'] CustomWizard::Template.save(new_template, skip_jobs: true) - put '/w/super-mega-fun-wizard/steps/step_1.json', params: { - fields: { - step_1_field_1: "Condition wont pass" - } - } + put '/w/super-mega-fun-wizard/steps/step_1.json' + put '/w/super-mega-fun-wizard/steps/step_2.json' + put '/w/super-mega-fun-wizard/steps/step_3.json' expect(response.status).to eq(200) expect(response.parsed_body['redirect_on_complete']).to eq("https://google.com") end it "saves results of completion actions if user has completed wizard" do new_template = wizard_template.dup - - ## Create group action new_template['actions'].first['run_after'] = 'wizard_completion' - new_template['steps'][1]['condition'] = wizard_field_condition_template['condition'] CustomWizard::Template.save(new_template, skip_jobs: true) put '/w/super-mega-fun-wizard/steps/step_1.json', params: { fields: { - step_1_field_1: "My cool group" + step_1_field_1: "Topic title", + step_1_field_2: "Topic post" } } - expect(response.status).to eq(200) - - put '/w/super-mega-fun-wizard/steps/step_3.json' - expect(response.status).to eq(200) + put '/w/super-mega-fun-wizard/steps/step_2.json' + put '/w/super-mega-fun-wizard/steps/step_3.json' wizard_id = response.parsed_body['wizard']['id'] wizard = CustomWizard::Wizard.create(wizard_id, user) - group_name = wizard.submissions.first.fields['action_9'] - group = Group.find_by(name: group_name) - - expect(group.present?).to eq(true) - expect(group.full_name).to eq("My cool group") + topic_id = wizard.submissions.first.fields[new_template['actions'].first['id']] + topic = Topic.find(topic_id) + expect(topic.present?).to eq(true) end it "returns a final step without conditions" do @@ -197,88 +119,119 @@ describe CustomWizard::StepsController do expect(response.parsed_body['final']).to eq(true) end - it "returns the correct final step when the conditional final step and last step are the same" do - new_template = wizard_template.dup - new_template['steps'][0]['condition'] = user_condition_template['condition'] - new_template['steps'][2]['condition'] = wizard_field_condition_template['condition'] - CustomWizard::Template.save(new_template, skip_jobs: true) + context "pro" do + before do + enable_pro + end - put '/w/super-mega-fun-wizard/steps/step_1.json', params: { - fields: { - step_1_field_1: "Condition will pass" + it "raises an error when user cant see the step due to conditions" do + sign_in(user2) + + new_wizard_template = wizard_template.dup + new_wizard_template['steps'][0]['condition'] = user_condition_template['condition'] + CustomWizard::Template.save(new_wizard_template, skip_jobs: true) + + put '/w/super-mega-fun-wizard/steps/step_1.json' + expect(response.status).to eq(403) + end + + it "returns an updated wizard when condition doesnt pass" do + new_template = wizard_template.dup + new_template['steps'][1]['condition'] = wizard_field_condition_template['condition'] + CustomWizard::Template.save(new_template, skip_jobs: true) + + put '/w/super-mega-fun-wizard/steps/step_1.json', params: { + fields: { + step_1_field_1: "Condition wont pass" + } } - } - expect(response.status).to eq(200) - expect(response.parsed_body['final']).to eq(false) + expect(response.status).to eq(200) + expect(response.parsed_body['wizard']['start']).to eq("step_3") + end - put '/w/super-mega-fun-wizard/steps/step_2.json' - expect(response.status).to eq(200) - expect(response.parsed_body['final']).to eq(false) + it "returns the correct final step when the conditional final step and last step are the same" do + new_template = wizard_template.dup + new_template['steps'][0]['condition'] = user_condition_template['condition'] + new_template['steps'][2]['condition'] = wizard_field_condition_template['condition'] + CustomWizard::Template.save(new_template, skip_jobs: true) - put '/w/super-mega-fun-wizard/steps/step_3.json' - expect(response.status).to eq(200) - expect(response.parsed_body['final']).to eq(true) - end - - it "returns the correct final step when the conditional final step and last step are different" do - new_template = wizard_template.dup - new_template['steps'][2]['condition'] = wizard_field_condition_template['condition'] - CustomWizard::Template.save(new_template, skip_jobs: true) - - put '/w/super-mega-fun-wizard/steps/step_1.json', params: { - fields: { - step_1_field_1: "Condition will not pass" + put '/w/super-mega-fun-wizard/steps/step_1.json', params: { + fields: { + step_1_field_1: "Condition will pass" + } } - } - expect(response.status).to eq(200) - expect(response.parsed_body['final']).to eq(false) + expect(response.status).to eq(200) + expect(response.parsed_body['final']).to eq(false) - put '/w/super-mega-fun-wizard/steps/step_2.json' - expect(response.status).to eq(200) - expect(response.parsed_body['final']).to eq(true) - end + put '/w/super-mega-fun-wizard/steps/step_2.json' + expect(response.status).to eq(200) + expect(response.parsed_body['final']).to eq(false) - it "returns the correct final step when the conditional final step is determined in the same action" do - new_template = wizard_template.dup - new_template['steps'][1]['condition'] = wizard_field_condition_template['condition'] - new_template['steps'][2]['condition'] = wizard_field_condition_template['condition'] - CustomWizard::Template.save(new_template, skip_jobs: true) + put '/w/super-mega-fun-wizard/steps/step_3.json' + expect(response.status).to eq(200) + expect(response.parsed_body['final']).to eq(true) + end - put '/w/super-mega-fun-wizard/steps/step_1.json', params: { - fields: { - step_1_field_1: "Condition will not pass" + it "returns the correct final step when the conditional final step and last step are different" do + new_template = wizard_template.dup + new_template['steps'][2]['condition'] = wizard_field_condition_template['condition'] + CustomWizard::Template.save(new_template, skip_jobs: true) + + put '/w/super-mega-fun-wizard/steps/step_1.json', params: { + fields: { + step_1_field_1: "Condition will not pass" + } } - } - expect(response.status).to eq(200) - expect(response.parsed_body['final']).to eq(true) - end + expect(response.status).to eq(200) + expect(response.parsed_body['final']).to eq(false) - it "excludes the non-included conditional fields from the submissions" do - new_template = wizard_template.dup - new_template['steps'][1]['fields'][0]['condition'] = wizard_field_condition_template['condition'] - CustomWizard::Template.save(new_template, skip_jobs: true) + put '/w/super-mega-fun-wizard/steps/step_2.json' + expect(response.status).to eq(200) + expect(response.parsed_body['final']).to eq(true) + end - put '/w/super-mega-fun-wizard/steps/step_1.json', params: { - fields: { - step_1_field_1: "Condition will pass" + it "returns the correct final step when the conditional final step is determined in the same action" do + new_template = wizard_template.dup + new_template['steps'][1]['condition'] = wizard_field_condition_template['condition'] + new_template['steps'][2]['condition'] = wizard_field_condition_template['condition'] + CustomWizard::Template.save(new_template, skip_jobs: true) + + put '/w/super-mega-fun-wizard/steps/step_1.json', params: { + fields: { + step_1_field_1: "Condition will not pass" + } } - } + expect(response.status).to eq(200) + expect(response.parsed_body['final']).to eq(true) + end - put '/w/super-mega-fun-wizard/steps/step_2.json', params: { - fields: { - step_2_field_1: "1995-04-23" + it "excludes the non-included conditional fields from the submissions" do + new_template = wizard_template.dup + new_template['steps'][1]['fields'][0]['condition'] = wizard_field_condition_template['condition'] + CustomWizard::Template.save(new_template, skip_jobs: true) + + put '/w/super-mega-fun-wizard/steps/step_1.json', params: { + fields: { + step_1_field_1: "Condition will pass" + } } - } - put '/w/super-mega-fun-wizard/steps/step_1.json', params: { - fields: { - step_1_field_1: "Condition will not pass" + put '/w/super-mega-fun-wizard/steps/step_2.json', params: { + fields: { + step_2_field_1: "1995-04-23" + } } - } - wizard_id = response.parsed_body['wizard']['id'] - wizard = CustomWizard::Wizard.create(wizard_id, user) - submission = wizard.current_submission - expect(submission.fields.keys).not_to include("step_2_field_1") + put '/w/super-mega-fun-wizard/steps/step_1.json', params: { + fields: { + step_1_field_1: "Condition will not pass" + } + } + + wizard_id = response.parsed_body['wizard']['id'] + wizard = CustomWizard::Wizard.create(wizard_id, user) + submission = wizard.current_submission + expect(submission.fields.keys).not_to include("step_2_field_1") + end end end diff --git a/spec/requests/custom_wizard/wizard_controller_spec.rb b/spec/requests/custom_wizard/wizard_controller_spec.rb index f2000bda..c28f8783 100644 --- a/spec/requests/custom_wizard/wizard_controller_spec.rb +++ b/spec/requests/custom_wizard/wizard_controller_spec.rb @@ -2,29 +2,12 @@ require_relative '../../plugin_helper' describe CustomWizard::WizardController do - fab!(:user) { - Fabricate( - :user, - username: 'angus', - email: "angus@email.com", - trust_level: TrustLevel[3] - ) - } - - let(:permitted_json) { - JSON.parse( - File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard/permitted.json" - ).read - ) - } + fab!(:user) { Fabricate(:user, username: 'angus', email: "angus@email.com", trust_level: TrustLevel[3]) } + let(:wizard_template) { get_wizard_fixture("wizard") } + let(:permitted_json) { get_wizard_fixture("wizard/permitted") } before do - CustomWizard::Template.save( - JSON.parse(File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json" - ).read), - skip_jobs: true) + CustomWizard::Template.save(wizard_template, skip_jobs: true) @template = CustomWizard::Template.find("super_mega_fun_wizard") sign_in(user) end diff --git a/spec/serializers/custom_wizard/basic_wizard_serializer_spec.rb b/spec/serializers/custom_wizard/basic_wizard_serializer_spec.rb index bf575827..6694e979 100644 --- a/spec/serializers/custom_wizard/basic_wizard_serializer_spec.rb +++ b/spec/serializers/custom_wizard/basic_wizard_serializer_spec.rb @@ -4,13 +4,10 @@ require_relative '../../plugin_helper' describe CustomWizard::BasicWizardSerializer do fab!(:user) { Fabricate(:user) } + let(:template) { get_wizard_fixture("wizard") } 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) + CustomWizard::Template.save(template, skip_jobs: true) json = CustomWizard::BasicWizardSerializer.new( CustomWizard::Builder.new("super_mega_fun_wizard", user).build, scope: Guardian.new(user) diff --git a/spec/serializers/custom_wizard/custom_field_serializer_spec.rb b/spec/serializers/custom_wizard/custom_field_serializer_spec.rb index 4f5ffd72..2cf92f52 100644 --- a/spec/serializers/custom_wizard/custom_field_serializer_spec.rb +++ b/spec/serializers/custom_wizard/custom_field_serializer_spec.rb @@ -4,12 +4,7 @@ require_relative '../../plugin_helper' describe CustomWizard::CustomFieldSerializer do fab!(:user) { Fabricate(:user) } - - let(:custom_field_json) { - JSON.parse(File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/custom_field/custom_fields.json" - ).read) - } + let(:custom_field_json) { get_wizard_fixture("custom_field/custom_fields") } it 'should return custom field attributes' do custom_field_json['custom_fields'].each do |field_json| diff --git a/spec/serializers/custom_wizard/pro/authentication_serializer_spec.rb b/spec/serializers/custom_wizard/pro/authentication_serializer_spec.rb new file mode 100644 index 00000000..53dd74c2 --- /dev/null +++ b/spec/serializers/custom_wizard/pro/authentication_serializer_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require_relative '../../../plugin_helper' + +describe CustomWizard::ProAuthenticationSerializer do + fab!(:user) { Fabricate(:user) } + + it 'should return pro authentication attributes' do + auth = CustomWizard::ProAuthentication.new(OpenStruct.new(key: '1234', auth_at: Time.now, auth_by: user.id)) + serialized = described_class.new(auth, root: false).as_json + + expect(serialized[:active]).to eq(true) + expect(serialized[:client_id]).to eq(auth.client_id) + expect(serialized[:auth_by]).to eq(auth.auth_by) + expect(serialized[:auth_at]).to eq(auth.auth_at) + end +end diff --git a/spec/serializers/custom_wizard/pro/subscription_serializer_spec.rb b/spec/serializers/custom_wizard/pro/subscription_serializer_spec.rb new file mode 100644 index 00000000..a775863e --- /dev/null +++ b/spec/serializers/custom_wizard/pro/subscription_serializer_spec.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require_relative '../../../plugin_helper' + +describe CustomWizard::ProSubscriptionSerializer do + it 'should return pro subscription attributes' do + sub = CustomWizard::ProSubscription.new(OpenStruct.new(type: 'community', updated_at: Time.now)) + serialized = described_class.new(sub, root: false).as_json + + expect(serialized[:active]).to eq(true) + expect(serialized[:type]).to eq('community') + expect(serialized[:updated_at]).to eq(sub.updated_at) + end +end diff --git a/spec/serializers/custom_wizard/pro_serializer_spec.rb b/spec/serializers/custom_wizard/pro_serializer_spec.rb new file mode 100644 index 00000000..45c1956e --- /dev/null +++ b/spec/serializers/custom_wizard/pro_serializer_spec.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require_relative '../../plugin_helper' + +describe CustomWizard::ProSerializer do + it 'should return pro attributes' do + pro = CustomWizard::Pro.new + serialized = described_class.new(pro, root: false) + + expect(serialized.server).to eq(pro.server) + expect(serialized.authentication.class).to eq(CustomWizard::ProAuthentication) + expect(serialized.subscription.class).to eq(CustomWizard::ProSubscription) + end +end diff --git a/spec/serializers/custom_wizard/wizard_field_serializer_spec.rb b/spec/serializers/custom_wizard/wizard_field_serializer_spec.rb index 1fa9671c..349b21f8 100644 --- a/spec/serializers/custom_wizard/wizard_field_serializer_spec.rb +++ b/spec/serializers/custom_wizard/wizard_field_serializer_spec.rb @@ -4,13 +4,10 @@ require_relative '../../plugin_helper' describe CustomWizard::FieldSerializer do fab!(:user) { Fabricate(:user) } + let(:template) { get_wizard_fixture("wizard") } before do - CustomWizard::Template.save( - JSON.parse(File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json" - ).read), - skip_jobs: true) + CustomWizard::Template.save(template, skip_jobs: true) @wizard = CustomWizard::Builder.new("super_mega_fun_wizard", user).build end diff --git a/spec/serializers/custom_wizard/wizard_serializer_spec.rb b/spec/serializers/custom_wizard/wizard_serializer_spec.rb index 2052639a..fe36d5a2 100644 --- a/spec/serializers/custom_wizard/wizard_serializer_spec.rb +++ b/spec/serializers/custom_wizard/wizard_serializer_spec.rb @@ -5,19 +5,11 @@ require_relative '../../plugin_helper' describe CustomWizard::WizardSerializer do fab!(:user) { Fabricate(:user) } fab!(:category) { Fabricate(:category) } - - let(:similar_topics_validation) { - JSON.parse(File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/field/validation/similar_topics.json" - ).read) - } + let(:template) { get_wizard_fixture("wizard") } + let(:similar_topics_validation) { get_wizard_fixture("field/validation/similar_topics") } before do - CustomWizard::Template.save( - JSON.parse(File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json" - ).read), - skip_jobs: true) + CustomWizard::Template.save(template, skip_jobs: true) @template = CustomWizard::Template.find('super_mega_fun_wizard') end diff --git a/spec/serializers/custom_wizard/wizard_step_serializer_spec.rb b/spec/serializers/custom_wizard/wizard_step_serializer_spec.rb index 35ce0fd2..53afa8e5 100644 --- a/spec/serializers/custom_wizard/wizard_step_serializer_spec.rb +++ b/spec/serializers/custom_wizard/wizard_step_serializer_spec.rb @@ -4,22 +4,8 @@ require_relative '../../plugin_helper' describe CustomWizard::StepSerializer do fab!(:user) { Fabricate(:user) } - - let(:wizard_template) { - JSON.parse( - File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/wizard.json" - ).read - ) - } - - let(:required_data_json) { - JSON.parse( - File.open( - "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/step/required_data.json" - ).read - ) - } + let(:wizard_template) { get_wizard_fixture("wizard") } + let(:required_data_json) { get_wizard_fixture("step/required_data") } before do CustomWizard::Template.save(wizard_template, skip_jobs: true)