# frozen_string_literal: true describe CustomWizard::Action do fab!(:user) do Fabricate( :user, name: "Angus", username: "angus", email: "angus@email.com", trust_level: TrustLevel[2], ) end fab!(:user1) do Fabricate( :user, name: "Angus One", username: "angus1", email: "angus_one@email.com", trust_level: TrustLevel[2], ) end fab!(:category) { Fabricate(:category, name: "cat1", slug: "cat-slug") } fab!(:tag) { Fabricate(:tag, name: "tag1") } fab!(:group) 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(:watch_categories) { get_wizard_fixture("actions/watch_categories") } let(:watch_tags) { get_wizard_fixture("actions/watch_tags") } let(:create_group) { get_wizard_fixture("actions/create_group") } let(:create_group_with_nonexistent_user) { get_wizard_fixture("actions/create_group_bad_user") } 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(:api_test_endpoint) { get_wizard_fixture("endpoints/test_endpoint") } let(:api_test_endpoint_body) { get_wizard_fixture("endpoints/test_endpoint_body") } let(:api_test_no_authorization) { get_wizard_fixture("api/no_authorization") } let(:guests_permitted) { get_wizard_fixture("wizard/guests_permitted") } def update_template(template) CustomWizard::Template.save(template, skip_jobs: true) @template = CustomWizard::Template.find("super_mega_fun_wizard") end let(:create_topic) do JSON.parse( File.open( "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/actions/create_topic.json", ).read, ) end let(:custom_field_json) do JSON.parse( File.open( "#{Rails.root}/plugins/discourse-custom-wizard/spec/fixtures/custom_field/custom_fields.json", ).read, ) end before do Group.refresh_automatic_group!(:trust_level_2) update_template(wizard_template) end describe "#create_topic" do it "works" do wizard = CustomWizard::Builder.new(@template[:id], user).build wizard.create_updater( wizard.steps.first.id, step_1_field_1: "Topic Title", step_1_field_2: "topic body", ).update wizard.create_updater(wizard.steps.second.id, {}).update wizard.create_updater(wizard.steps.last.id, step_3_field_3: category.id).update topic = Topic.where(title: "Topic Title", category_id: category.id) expect(topic.exists?).to eq(true) expect(Post.where(topic_id: topic.pluck(:id), raw: "topic body").exists?).to eq(true) end it "fails silently without basic topic inputs" do wizard = CustomWizard::Builder.new(@template[:id], user).build wizard.create_updater(wizard.steps.first.id, step_1_field_2: "topic body").update wizard.create_updater(wizard.steps.second.id, {}).update updater = wizard.create_updater(wizard.steps.last.id, {}) updater.update expect(updater.success?).to eq(true) expect( CustomWizard::UserHistory.where( actor_id: user.id, context: "super_mega_fun_wizard", subject: "step_3", ).exists?, ).to eq(true) expect(Post.where(raw: "topic body").exists?).to eq(false) end it "adds custom fields" do wizard = CustomWizard::Builder.new(@template[:id], user).build wizard.create_updater( wizard.steps.first.id, step_1_field_1: "Topic Title", step_1_field_2: "topic body", ).update wizard.create_updater(wizard.steps.second.id, {}).update wizard.create_updater(wizard.steps.last.id, step_3_field_3: category.id).update topic = Topic.where(title: "Topic Title", category_id: category.id).first topic_custom_field = TopicCustomField.where( name: "topic_field", value: "Topic custom field value", topic_id: topic.id, ) topic_json_custom_field = TopicCustomField.where( " name = 'topic_json_field' AND (value::json->>'key_1') = 'Key 1 value' AND (value::json->>'key_2') = 'Key 2 value' AND topic_id = #{topic.id}", ) post_custom_field = PostCustomField.where( name: "post_field", value: "Post custom field value", post_id: topic.first_post.id, ) expect(topic_custom_field.exists?).to eq(true) expect(topic_json_custom_field.exists?).to eq(true) expect(post_custom_field.exists?).to eq(true) end it "adds registered custom fields" do custom_field = custom_field_json["custom_fields"][0] custom_field_name = custom_field["name"] custom_field_value = "Custom value" CustomWizard::CustomField.new(nil, custom_field).save create_topic["custom_fields"] = [ { type: "association", pairs: [ { index: 0, key: custom_field_name, key_type: "custom_field", value: custom_field_value, value_type: "text", connector: "association", }, ], }, ] wizard = CustomWizard::Wizard.new(@template, user) action = CustomWizard::Action.new( wizard: wizard, action: create_topic.with_indifferent_access, submission: wizard.current_submission, ) action.perform expect(action.result.success?).to eq(true) expect(TopicCustomField.exists?(name: custom_field_name)).to eq(true) end it "allows poster to be set" do wizard_template[:actions][0]["poster"] = [ { type: "assignment", output_type: "user", output_connector: "set", output: ["angus1"] }, ] update_template(wizard_template) wizard = CustomWizard::Builder.new(@template[:id], user).build wizard.create_updater( wizard.steps.first.id, step_1_field_1: "Topic Title", step_1_field_2: "topic body", ).update wizard.create_updater(wizard.steps.second.id, {}).update wizard.create_updater(wizard.steps.last.id, step_3_field_3: category.id).update topic = Topic.where(title: "Topic Title", category_id: category.id) expect(topic.exists?).to eq(true) post = Post.find_by(topic_id: topic.pluck(:id), raw: "topic body") expect(post.present?).to eq(true) expect(post.user.username).to eq("angus1") end end it "updates a profile" do wizard = CustomWizard::Builder.new(@template[:id], user).build upload = Upload.create!( url: "/images/image.png", original_filename: "image.png", filesize: 100, user_id: -1, ) steps = wizard.steps wizard.create_updater(steps[0].id, {}).update wizard.create_updater( steps[1].id, step_2_field_7: upload.as_json(only: %i[id url user_id]), ).update expect(user.profile_background_upload.id).to eq(upload.id) end context "open composer" do it "works" do wizard = CustomWizard::Builder.new(@template[:id], user).build wizard.create_updater(wizard.steps[0].id, step_1_field_1: "Text input").update updater = wizard.create_updater(wizard.steps[1].id, {}) updater.update 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&tags=tag1", ) end it "encodes special characters in the title and body" do open_composer["title"][0]["output"] = "Title that's special $".dup open_composer["post_template"] = "Body & more body & more body".dup wizard = CustomWizard::Wizard.new(@template, user) action = CustomWizard::Action.new( wizard: wizard, action: open_composer, submission: wizard.current_submission, ) action.perform expect(action.result.success?).to eq(true) decoded_output = CGI.parse(URI.parse(action.result.output).query) expect(decoded_output["title"][0]).to eq("Title that's special $") expect(decoded_output["body"][0]).to eq("Body & more body & more body") end end context "route to action" do it "re-routes a user" do wizard = CustomWizard::Builder.new(@template[:id], user).build updater = wizard.create_updater(wizard.steps.last.id, {}) updater.update expect(updater.result[:redirect_on_next]).to eq("https://google.com") end it "works if the code field has a blank string" do wizard_template[:actions].last[:code] = " " update_template(wizard_template) wizard = CustomWizard::Builder.new(@template[:id], user).build updater = wizard.create_updater(wizard.steps.last.id, {}) updater.update expect(updater.result[:redirect_on_next]).to eq("https://google.com") end end context "standard subscription actions" do before do enable_subscription("standard") Jobs.run_immediately! end it "watches tags" do watch_tags[:tags][0][:output] = tag.name wizard_template[:actions] << watch_tags 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(TagUser.where(tag_id: tag.id, user_id: user.id).first.notification_level).to eq(2) end it "watches categories" do watch_categories[:categories][0][:output] = category.id wizard_template[:actions] << watch_categories 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( CategoryUser.where(category_id: category.id, user_id: user.id).first.notification_level, ).to eq(2) end it "#send_message" do Jobs.run_immediately! target_user = Fabricate(:user) send_message["recipient"][0]["output"][0] = target_user.username wizard_template["actions"] << send_message update_template(wizard_template) 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(target_user.username) expect(post.exists?).to eq(true) expect(target_user.reload.notifications.count).to eq(1) end it "#send_message allows using multiple targets" do Jobs.run_immediately! user1 = Fabricate(:user) user2 = Fabricate(:user) group1 = Fabricate(:group) group2 = Fabricate(:group) send_message_multi["recipient"][0]["output"] = [ user1.username, user2.username, group1.name, group2.name, ] wizard_template["actions"] << send_message_multi update_template(wizard_template) update_template(wizard_template) 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( user1.username, user2.username, ) expect(topic.first.allowed_groups.map(&:name)).to include(group1.name, group2.name) expect(post.exists?).to eq(true) expect(user1.reload.notifications.count).to eq(1) expect(user2.reload.notifications.count).to eq(1) end context "with a guest" do describe "#create_topic" do before do Jobs.run_immediately! wizard_template["permitted"] = guests_permitted["permitted"] wizard_template[:steps][0][:fields] << { id: "step_1_field_5", label: "Guest Email", type: "text", min_length: "3", }.as_json create_topic["run_after"] = "step_3" create_topic["guest_email"] = [ { type: "assignment", output: "step_1_field_5", output_type: "wizard_field", output_connector: "set", }, ] create_topic["category"] = [ { type: "assignment", output: "step_3_field_3", output_type: "wizard_field", output_connector: "set", }, ] wizard_template.delete("actions") wizard_template[:actions] = [create_topic] update_template(wizard_template) end it "creates a staged guest poster if guest_email is set" do wizard = CustomWizard::Builder.new( @template[:id], nil, CustomWizard::Wizard.generate_guest_id, ).build wizard.create_updater(wizard.steps.first.id, step_1_field_5: "guest@email.com").update wizard.create_updater(wizard.steps.second.id, {}).update wizard.create_updater(wizard.steps.last.id, step_3_field_3: category.id).update topic = Topic.where(category_id: category.id).first expect(topic.present?).to eq(true) expect(topic.posts.first.user.staged).to eq(true) expect(topic.posts.first.user.primary_email.email).to eq("guest@email.com") end it "returns an existing user with the same email" do existing = Fabricate(:user, email: "guest@email.com") wizard = CustomWizard::Builder.new( @template[:id], nil, CustomWizard::Wizard.generate_guest_id, ).build wizard.create_updater(wizard.steps.first.id, step_1_field_5: "guest@email.com").update wizard.create_updater(wizard.steps.second.id, {}).update wizard.create_updater(wizard.steps.last.id, step_3_field_3: category.id).update topic = Topic.where(category_id: category.id).first expect(topic.present?).to eq(true) expect(topic.posts.first.user.staged).to eq(false) expect(topic.posts.first.user.primary_email.email).to eq("guest@email.com") end end describe "#send_message" do it "works" do wizard_template["permitted"] = guests_permitted["permitted"] wizard_template.delete("actions") wizard_template["actions"] = [send_message] update_template(wizard_template) wizard = CustomWizard::Builder.new( wizard_template["id"], nil, CustomWizard::Wizard.generate_guest_id, ).build wizard.create_updater(wizard.steps[0].id, {}).update updater = wizard.create_updater(wizard.steps[1].id, {}) updater.update topic = Topic.where(archetype: Archetype.private_message, title: "Message title") post = Post.where(topic_id: topic.pluck(:id)) expect(topic.exists?).to eq(true) expect(topic.first.topic_allowed_users.first.user.username).to eq(user1.username) expect(topic.first.topic_allowed_users.second.user.username).to eq( Discourse.system_user.username, ) expect(post.exists?).to eq(true) end it "works when the target is an email address" do Jobs.run_immediately! wizard_template["permitted"] = guests_permitted["permitted"] wizard_template.delete("actions") send_message["recipient"] = [ { type: "assignment", output: "step_1_field_1", output_type: "wizard_field", output_connector: "set", }, ] wizard_template["actions"] = [send_message] update_template(wizard_template) NotificationEmailer.expects(:process_notification).once wizard = CustomWizard::Builder.new( wizard_template["id"], nil, CustomWizard::Wizard.generate_guest_id, ).build wizard.create_updater(wizard.steps[0].id, step_1_field_1: "guest@email.com").update updater = wizard.create_updater(wizard.steps[1].id, {}) updater.update topic = Topic.where(archetype: Archetype.private_message, title: "Message title") post = Post.where(topic_id: topic.pluck(:id)) expect(topic.exists?).to eq(true) expect(topic.first.topic_allowed_users.first.user.staged).to eq(true) expect(topic.first.topic_allowed_users.first.user.primary_email.email).to eq( "guest@email.com", ) expect(topic.first.topic_allowed_users.second.user.username).to eq( Discourse.system_user.username, ) expect(post.exists?).to eq(true) end end end end context "business subscription actions" do before { enable_subscription("business") } it "#create_category" do wizard_template["actions"] << create_category 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 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 group_id = Group.where(name: wizard.current_submission.fields["action_9"]).first.id user_id = User.find_by(username: wizard_template["actions"][4]["usernames"][0]["output"][0]).id expect(Group.where(name: wizard.current_submission.fields["action_9"]).exists?).to eq(true) expect(GroupUser.where(group_id: group_id, user_id: user_id).exists?).to eq(true) end it "#create_group completes successfully when user included in usernames does not exist but excludes users who do not exist and includes warning in log" do wizard_template["actions"] << create_group_with_nonexistent_user 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 group_id = Group.where(name: wizard.current_submission.fields["action_9"]).first.id expect( CustomWizard::Log.list_query.all.last.value.include? "some users were not found" ).to eq(true) expect(Group.where(name: wizard.current_submission.fields["action_9"]).exists?).to eq(true) expect(GroupUser.where(group_id: group_id).count).to eq(1) 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 it "#send_to_api successful" do stub_request(:put, "https://myexternalapi.com/update").with( body: "some_body", headers: { "Host" => "myexternalapi.com", }, ).to_return(status: 200, body: "success", headers: {}) new_api = CustomWizard::Api.new("my_api") CustomWizard::Api.set("my_api", title: "Mocked external api") CustomWizard::Api::Authorization.set("my_api", api_test_no_authorization) CustomWizard::Api::Endpoint.new("my_api") CustomWizard::Api::Endpoint.set("my_api", api_test_endpoint) endpoint_id = CustomWizard::Api::Endpoint.list("my_api").first.id result = CustomWizard::Api::Endpoint.request("my_api", endpoint_id, "some_body") log_entry = CustomWizard::Api::LogEntry.list("my_api").first expect(result).to eq("success") expect(log_entry.status).to eq("SUCCESS") end it "#send_to_api failure" do stub_request(:put, "https://myexternalapi.com/update").with( body: "some_body", headers: { "Host" => "myexternalapi.com", }, ).to_return(status: 500, body: "failure", headers: {}) new_api = CustomWizard::Api.new("my_api") CustomWizard::Api.set("my_api", title: "Mocked external api") CustomWizard::Api::Authorization.set("my_api", api_test_no_authorization) CustomWizard::Api::Endpoint.new("my_api") CustomWizard::Api::Endpoint.set("my_api", api_test_endpoint) endpoint_id = CustomWizard::Api::Endpoint.list("my_api").first.id result = CustomWizard::Api::Endpoint.request("my_api", endpoint_id, "some_body") log_entry = CustomWizard::Api::LogEntry.list("my_api").first expect(result).to eq({ error: "API request failed" }) expect(log_entry.status).to eq("FAIL") end end it "registers callbacks" do described_class.register_callback(:before_create_topic) do |params, wizard, action, submission| params[:topic_opts][:custom_fields]["topic_custom_field"] = true params end wizard = CustomWizard::Builder.new(@template[:id], user).build action = CustomWizard::Action.new( wizard: wizard, action: create_topic.with_indifferent_access, submission: wizard.current_submission, ) action.perform expect(action.result.success?).to eq(true) expect(Topic.find(action.result.output).custom_fields["topic_custom_field"]).to eq("t") end context "creating a topic when there are multiple actions" do it "works" do wizard_template["actions"] << create_topic wizard_template["actions"] << send_message update_template(wizard_template) wizard = CustomWizard::Builder.new(@template[:id], user).build wizard.create_updater( wizard.steps.first.id, step_1_field_1: "Topic Title", step_1_field_2: "topic body", ).update wizard.create_updater(wizard.steps.second.id, {}).update wizard.create_updater(wizard.steps.last.id, step_3_field_3: category.id).update wizard.create_updater(wizard.steps[0].id, {}).update wizard.create_updater(wizard.steps[1].id, {}).update topic = Topic.where(title: "Topic Title", category_id: category.id) expect(topic.exists?).to eq(true) expect(Post.where(topic_id: topic.pluck(:id), raw: "topic body").exists?).to eq(true) end end end