From 441ad49bf62f69148b69e93406c2ecb7ac925168 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Mon, 8 Jul 2024 11:58:24 +0200 Subject: [PATCH 1/7] Add email address support to send_message recipients See further https://coop.pavilion.tech/t/custom-wizard-pm-access-and-send-copy-of-submission-for-guest-users/3600 --- lib/custom_wizard/action.rb | 8 +++-- spec/components/custom_wizard/action_spec.rb | 37 +++++++++++++++++++- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/lib/custom_wizard/action.rb b/lib/custom_wizard/action.rb index 9fe725e7..7972f92c 100644 --- a/lib/custom_wizard/action.rb +++ b/lib/custom_wizard/action.rb @@ -119,20 +119,22 @@ class CustomWizard::Action params[:target_group_names] = [] params[:target_usernames] = [] + params[:target_emails] = [] [*targets].each do |target| if Group.find_by(name: target) params[:target_group_names] << target elsif User.find_by_username(target) params[:target_usernames] << target - else - # + elsif target.match(/@/) # Compare discourse/discourse/app/controllers/posts_controller.rb#L922-L923 + params[:target_emails] << target end end if params[:title].present? && params[:raw].present? && (params[:target_usernames].present? || - params[:target_group_names].present?) + params[:target_group_names].present? || + params[:target_emails].present?) params[:archetype] = Archetype.private_message diff --git a/spec/components/custom_wizard/action_spec.rb b/spec/components/custom_wizard/action_spec.rb index 03deab27..4ce6d842 100644 --- a/spec/components/custom_wizard/action_spec.rb +++ b/spec/components/custom_wizard/action_spec.rb @@ -333,7 +333,7 @@ describe CustomWizard::Action do expect(user2.reload.notifications.count).to eq(1) end - it "send_message works with guests are permitted" do + it "send_message works when guests are permitted" do wizard_template["permitted"] = guests_permitted["permitted"] wizard_template.delete("actions") wizard_template['actions'] = [send_message] @@ -354,6 +354,41 @@ describe CustomWizard::Action do expect(topic.first.topic_allowed_users.second.user.username).to eq(Discourse.system_user.username) expect(post.exists?).to eq(true) end + + it "send_message works when guests are permitted and 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 context "business subscription actions" do From cff8f9f427d41705f41deffeabfdf6317e7db780 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Tue, 9 Jul 2024 11:23:57 +0200 Subject: [PATCH 2/7] Add poster and guest_email to topic and message creation && allow guests to create_topic --- app/controllers/custom_wizard/admin/wizard.rb | 2 + .../components/wizard-custom-action.js.es6 | 1 + .../components/wizard-mapper-selector.js.es6 | 14 ++ .../discourse/components/wizard-mapper.js.es6 | 2 + .../components/wizard-user-chooser.js.es6 | 55 ++++++ .../wizard-user-chooser-row.js | 5 + .../discourse/lib/wizard-schema.js.es6 | 5 + .../components/wizard-custom-action.hbs | 43 ++++ .../components/wizard-mapper-selector.hbs | 4 +- .../wizard-user-chooser-row.hbs | 20 ++ config/locales/client.en.yml | 6 + lib/custom_wizard/action.rb | 47 ++++- lib/custom_wizard/field.rb | 1 - spec/components/custom_wizard/action_spec.rb | 183 +++++++++++++----- .../custom_wizard/template_validator_spec.rb | 3 - 15 files changed, 336 insertions(+), 55 deletions(-) create mode 100644 assets/javascripts/discourse/components/wizard-user-chooser.js.es6 create mode 100644 assets/javascripts/discourse/components/wizard-user-chooser/wizard-user-chooser-row.js create mode 100644 assets/javascripts/discourse/templates/components/wizard-user-chooser/wizard-user-chooser-row.hbs diff --git a/app/controllers/custom_wizard/admin/wizard.rb b/app/controllers/custom_wizard/admin/wizard.rb index 955deb3f..993d0e6c 100644 --- a/app/controllers/custom_wizard/admin/wizard.rb +++ b/app/controllers/custom_wizard/admin/wizard.rb @@ -145,6 +145,8 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController custom_fields: mapped_params, visible: mapped_params, required: mapped_params, + poster: mapped_params, + guest_email: mapped_params, recipient: mapped_params, categories: mapped_params, mute_remainder: mapped_params, diff --git a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 b/assets/javascripts/discourse/components/wizard-custom-action.js.es6 index b9329617..1f4c914a 100644 --- a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 +++ b/assets/javascripts/discourse/components/wizard-custom-action.js.es6 @@ -5,6 +5,7 @@ import { computed } from "@ember/object"; import UndoChanges from "../mixins/undo-changes"; import Component from "@ember/component"; import I18n from "I18n"; +import { WIZARD_USER } from "./wizard-user-chooser"; export default Component.extend(UndoChanges, { componentType: "action", diff --git a/assets/javascripts/discourse/components/wizard-mapper-selector.js.es6 b/assets/javascripts/discourse/components/wizard-mapper-selector.js.es6 index eb9e735a..5d67b8f7 100644 --- a/assets/javascripts/discourse/components/wizard-mapper-selector.js.es6 +++ b/assets/javascripts/discourse/components/wizard-mapper-selector.js.es6 @@ -121,6 +121,9 @@ export default Component.extend({ guestGroup: computed("options.guestGroup", "inputType", function () { return this.optionEnabled("guestGroup"); }), + includeMessageableGroups: computed("options.includeMessageableGroups", "inputType", function () { + return this.optionEnabled("includeMessageableGroups"); + }), userEnabled: computed("options.userSelection", "inputType", function () { return this.optionEnabled("userSelection"); }), @@ -352,6 +355,17 @@ export default Component.extend({ return result; }, + @discourseComputed("includeMessageableGroups", "options.userLimit") + userOptions(includeMessageableGroups, userLimit) { + const opts = { + includeMessageableGroups + } + if (userLimit) { + opts.maximum = userLimit + } + return opts; + }, + optionEnabled(type) { const options = this.options; if (!options) { diff --git a/assets/javascripts/discourse/components/wizard-mapper.js.es6 b/assets/javascripts/discourse/components/wizard-mapper.js.es6 index ec58e3f2..16e2e570 100644 --- a/assets/javascripts/discourse/components/wizard-mapper.js.es6 +++ b/assets/javascripts/discourse/components/wizard-mapper.js.es6 @@ -33,6 +33,8 @@ export default Component.extend({ outputConnector: options.outputConnector || null, context: options.context || null, guestGroup: options.guestGroup || false, + includeMessageableGroups: options.includeMessageableGroups || false, + userLimit: options.userLimit || null }; let inputTypes = ["key", "value", "output"]; diff --git a/assets/javascripts/discourse/components/wizard-user-chooser.js.es6 b/assets/javascripts/discourse/components/wizard-user-chooser.js.es6 new file mode 100644 index 00000000..d52c733d --- /dev/null +++ b/assets/javascripts/discourse/components/wizard-user-chooser.js.es6 @@ -0,0 +1,55 @@ +import UserChooserComponent from "select-kit/components/user-chooser"; + +export const WIZARD_USER = "wizard-user"; + +export default UserChooserComponent.extend({ + pluginApiIdentifiers: ["wizard-user-chooser"], + classNames: ["user-chooser", "wizard-user-chooser"], + classNameBindings: ["selectKit.options.fullWidthWrap:full-width-wrap"], + valueProperty: "id", + nameProperty: "name", + + modifyComponentForRow() { + return "wizard-user-chooser/wizard-user-chooser-row"; + }, + + modifyNoSelection() { + return this.defaultItem(WIZARD_USER, I18n.t("admin.wizard.action.poster.wizard_user")); + }, + + selectKitOptions: { + fullWidthWrap: false, + autoWrap: false, + }, + + search() { + const superPromise = this._super(...arguments); + if (!superPromise) { + return; + } + return superPromise.then((results) => { + console.log(results) + if (!results || results.length === 0) { + return; + } + return results.map((item) => { + const reconstructed = {}; + if (item.username) { + reconstructed.id = item.username; + if (item.username.includes("@")) { + reconstructed.isEmail = true; + } else { + reconstructed.isUser = true; + reconstructed.name = item.name; + reconstructed.showUserStatus = this.showUserStatus; + } + } else if (item.name) { + reconstructed.id = item.name; + reconstructed.name = item.full_name; + reconstructed.isGroup = true; + } + return { ...item, ...reconstructed }; + }); + }); + }, +}); diff --git a/assets/javascripts/discourse/components/wizard-user-chooser/wizard-user-chooser-row.js b/assets/javascripts/discourse/components/wizard-user-chooser/wizard-user-chooser-row.js new file mode 100644 index 00000000..125bccca --- /dev/null +++ b/assets/javascripts/discourse/components/wizard-user-chooser/wizard-user-chooser-row.js @@ -0,0 +1,5 @@ +import SelectKitRowComponent from "select-kit/components/select-kit/select-kit-row"; + +export default SelectKitRowComponent.extend({ + classNames: ["user-row", "wizard-user-chooser-row"], +}); diff --git a/assets/javascripts/discourse/lib/wizard-schema.js.es6 b/assets/javascripts/discourse/lib/wizard-schema.js.es6 index 710a3594..0c76fa53 100644 --- a/assets/javascripts/discourse/lib/wizard-schema.js.es6 +++ b/assets/javascripts/discourse/lib/wizard-schema.js.es6 @@ -100,6 +100,8 @@ const action = { custom_fields: null, skip_redirect: null, suppress_notifications: null, + poster: 'wizard-user', + guest_email: null, add_event: null, add_location: null, }, @@ -111,6 +113,8 @@ const action = { skip_redirect: null, custom_fields: null, required: null, + poster: 'wizard-user', + guest_email: null, recipient: null, suppress_notifications: null, }, @@ -184,6 +188,7 @@ const action = { "custom_fields", "required", "recipient", + "poster", "profile_updates", "group", "url", diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs index 80152674..1116d79f 100644 --- a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs @@ -98,6 +98,48 @@ {{/if}} + +
+
+ +
+ +
+ {{wizard-mapper + inputs=this.action.poster + property="poster" + onUpdate=(action "mappedFieldUpdated") + options=(hash + textSelection='key,value' + wizardFieldSelection=true + userSelection="output" + outputDefaultSelection="user" + userLimit="1" + context="action" + ) + }} +
+
+ +
+
+ +
+ +
+ {{wizard-mapper + inputs=this.action.guest_email + property="guest_email" + onUpdate=(action "mappedFieldUpdated") + options=(hash + textSelection="key,value" + wizardFieldSelection=true + outputPlaceholder="admin.wizard.action.guest_email.placeholder" + context="action" + ) + }} +
+
{{/if}} {{#if publicTopicFields}} @@ -217,6 +259,7 @@ userSelection="output" outputDefaultSelection="user" context="action" + includeMessageableGroups="true" ) }} diff --git a/assets/javascripts/discourse/templates/components/wizard-mapper-selector.hbs b/assets/javascripts/discourse/templates/components/wizard-mapper-selector.hbs index 80669aa4..3971cd26 100644 --- a/assets/javascripts/discourse/templates/components/wizard-mapper-selector.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-mapper-selector.hbs @@ -66,12 +66,12 @@ {{/if}} {{#if showUser}} - {{email-group-user-chooser + {{wizard-user-chooser placeholderKey=placeholderKey value=value autocomplete="discourse" onChange=(action "changeUserValue") - options=(hash includeMessageableGroups="true") + options=userOptions }} {{/if}} \ No newline at end of file diff --git a/assets/javascripts/discourse/templates/components/wizard-user-chooser/wizard-user-chooser-row.hbs b/assets/javascripts/discourse/templates/components/wizard-user-chooser/wizard-user-chooser-row.hbs new file mode 100644 index 00000000..8ff700b0 --- /dev/null +++ b/assets/javascripts/discourse/templates/components/wizard-user-chooser/wizard-user-chooser-row.hbs @@ -0,0 +1,20 @@ +{{#if this.item.isUser}} + {{avatar this.item imageSize="tiny"}} +
+ {{format-username this.item.id}} + {{this.item.name}} +
+ {{#if (and this.item.showUserStatus this.item.status)}} + + {{/if}} + {{decorate-username-selector this.item.id}} +{{else if this.item.isGroup}} + {{d-icon "users"}} +
+ {{this.item.id}} + {{this.item.full_name}} +
+{{else}} + {{d-icon "envelope"}} + {{this.item.id}} +{{/if}} \ No newline at end of file diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 71d5eeac..3e7feba1 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -344,6 +344,12 @@ en: include: "Include Fields" title: "Title" post: "Post" + poster: + label: "Poster" + wizard_user: "Wizard user" + guest_email: + label: "Guest email" + placeholder: "Field for guest email" topic_attr: "Topic Attribute" interpolate_fields: "Insert wizard fields using the field_id in w{}. Insert user fields using field key in u{}." diff --git a/lib/custom_wizard/action.rb b/lib/custom_wizard/action.rb index 7972f92c..d539d785 100644 --- a/lib/custom_wizard/action.rb +++ b/lib/custom_wizard/action.rb @@ -7,13 +7,14 @@ class CustomWizard::Action :result REQUIRES_USER = %w[ - create_topic update_profile open_composer watch_categories add_to_group ] + WIZARD_USER = 'wizard-user' + def initialize(opts) @wizard = opts[:wizard] @action = opts[:action] @@ -69,7 +70,7 @@ class CustomWizard::Action end if params[:title].present? && params[:raw].present? - creator = PostCreator.new(user, params) + creator = PostCreator.new(topic_poster, params) post = creator.create if creator.errors.present? @@ -138,8 +139,7 @@ class CustomWizard::Action params[:archetype] = Archetype.private_message - poster = user || Discourse.system_user - creator = PostCreator.new(poster, params) + creator = PostCreator.new(topic_poster, params) post = creator.create if creator.errors.present? @@ -653,6 +653,45 @@ class CustomWizard::Action params end + def topic_poster + @topic_poster ||= begin + poster_id = CustomWizard::Mapper.new( + inputs: action['poster'], + data: mapper_data, + user: user, + ).perform + poster_id = [*poster_id].first if poster_id.present? + + if poster_id.blank? || poster_id === WIZARD_USER + poster = user || guest_user + else + poster = User.find_by_username(poster_id) + end + + poster || Discourse.system_user + end + end + + def guest_user + @guest_user ||= begin + return nil unless action['guest_email'] + + email = CustomWizard::Mapper.new( + inputs: action['guest_email'], + data: mapper_data, + ).perform + + if email&.match(/@/) + User.create!( + email: email, + username: UserNameSuggester.suggest(email), + name: User.suggest_name(email), + staged: true, + ) + end + end + end + def new_group_params params = {} diff --git a/lib/custom_wizard/field.rb b/lib/custom_wizard/field.rb index e8e7bbf9..c0ebaae3 100644 --- a/lib/custom_wizard/field.rb +++ b/lib/custom_wizard/field.rb @@ -31,7 +31,6 @@ class CustomWizard::Field :step REQUIRES_USER = %w[ - composer upload ] diff --git a/spec/components/custom_wizard/action_spec.rb b/spec/components/custom_wizard/action_spec.rb index 4ce6d842..13f1b13f 100644 --- a/spec/components/custom_wizard/action_spec.rb +++ b/spec/components/custom_wizard/action_spec.rb @@ -46,7 +46,7 @@ describe CustomWizard::Action do update_template(wizard_template) end - context 'creating a topic' do + describe '#create_topic' do it "works" do wizard = CustomWizard::Builder.new(@template[:id], user).build wizard.create_updater( @@ -160,6 +160,43 @@ describe CustomWizard::Action do 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 @@ -234,6 +271,7 @@ describe CustomWizard::Action do context "standard subscription actions" do before do enable_subscription("standard") + Jobs.run_immediately! end it 'watches tags' do @@ -333,61 +371,117 @@ describe CustomWizard::Action do expect(user2.reload.notifications.count).to eq(1) end - it "send_message works when guests are permitted" do - wizard_template["permitted"] = guests_permitted["permitted"] - wizard_template.delete("actions") - wizard_template['actions'] = [send_message] - update_template(wizard_template) + context "with a guest" do + describe "#create_topic" do + it "creates a staged guest poster if guest_email is set" do + Jobs.run_immediately! - User.create(username: 'angus1', email: "angus1@email.com") + 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] - 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 + update_template(wizard_template) - topic = Topic.where(archetype: Archetype.private_message, title: "Message title") - post = Post.where(topic_id: topic.pluck(:id)) + 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 - expect(topic.exists?).to eq(true) - expect(topic.first.topic_allowed_users.first.user.username).to eq('angus1') - expect(topic.first.topic_allowed_users.second.user.username).to eq(Discourse.system_user.username) - expect(post.exists?).to eq(true) - end + 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 + end - it "send_message works when guests are permitted and the target is an email address" do - Jobs.run_immediately! + 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_template["permitted"] = guests_permitted["permitted"] - wizard_template.delete("actions") + 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 - send_message["recipient"] = [ - { - "type": "assignment", - "output": "step_1_field_1", - "output_type": "wizard_field", - "output_connector": "set" - } - ] + topic = Topic.where(archetype: Archetype.private_message, title: "Message title") + post = Post.where(topic_id: topic.pluck(:id)) - wizard_template['actions'] = [send_message] - update_template(wizard_template) + 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 - NotificationEmailer.expects(:process_notification).once + it "works when the target is an email address" do + Jobs.run_immediately! - 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 + wizard_template["permitted"] = guests_permitted["permitted"] + wizard_template.delete("actions") - topic = Topic.where(archetype: Archetype.private_message, title: "Message title") - post = Post.where(topic_id: topic.pluck(:id)) + send_message["recipient"] = [ + { + "type": "assignment", + "output": "step_1_field_1", + "output_type": "wizard_field", + "output_connector": "set" + } + ] - 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) + 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 @@ -528,7 +622,6 @@ describe CustomWizard::Action do wizard.create_updater(wizard.steps.second.id, {}).update wizard.create_updater(wizard.steps.last.id, step_3_field_3: category.id) .update - User.create(username: 'angus1', email: 'angus1@email.com') 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) diff --git a/spec/components/custom_wizard/template_validator_spec.rb b/spec/components/custom_wizard/template_validator_spec.rb index fe61be91..38288409 100644 --- a/spec/components/custom_wizard/template_validator_spec.rb +++ b/spec/components/custom_wizard/template_validator_spec.rb @@ -155,9 +155,6 @@ describe CustomWizard::TemplateValidator do validator = CustomWizard::TemplateValidator.new(template) expect(validator.perform).to eq(false) errors = validator.errors.to_a - expect(errors).to include( - I18n.t("wizard.validation.not_permitted_for_guests", object_id: "action_1") - ) expect(errors).to include( I18n.t("wizard.validation.not_permitted_for_guests", object_id: "step_2_field_7") ) From 54a9e9470e389aa482dc94108ea03c512eda50a3 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Tue, 9 Jul 2024 11:24:40 +0200 Subject: [PATCH 3/7] Add login button when no_access reason is requiresLogin --- .../components/custom-wizard-no-access.js.es6 | 12 ++++++++++++ .../components/custom-wizard-no-access.hbs | 16 +++++++++++----- assets/stylesheets/common/wizard/wizard.scss | 7 ++++++- config/locales/client.en.yml | 2 +- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/assets/javascripts/discourse/components/custom-wizard-no-access.js.es6 b/assets/javascripts/discourse/components/custom-wizard-no-access.js.es6 index b3b2e26c..4a7f4889 100644 --- a/assets/javascripts/discourse/components/custom-wizard-no-access.js.es6 +++ b/assets/javascripts/discourse/components/custom-wizard-no-access.js.es6 @@ -3,6 +3,8 @@ import discourseComputed from "discourse-common/utils/decorators"; import Component from "@ember/component"; import { dasherize } from "@ember/string"; import getURL from "discourse-common/lib/get-url"; +import cookie from "discourse/lib/cookie"; +import { getOwner } from "@ember/application"; export default Component.extend({ classNameBindings: [":wizard-no-access", "reasonClass"], @@ -17,6 +19,11 @@ export default Component.extend({ return this.siteSettings.title || ""; }, + @discourseComputed("reason") + showLoginButton(reason) { + return reason === "requiresLogin"; + }, + actions: { skip() { if (this.currentUser) { @@ -25,5 +32,10 @@ export default Component.extend({ window.location = getURL("/"); } }, + + showLogin() { + cookie("destination_url", getURL(`/w/${this.get("wizardId")}`)); + getOwner(this).lookup("route:application").send("showLogin"); + } }, }); diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-no-access.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-no-access.hbs index cb9f59f1..5ba51a61 100644 --- a/assets/javascripts/discourse/templates/components/custom-wizard-no-access.hbs +++ b/assets/javascripts/discourse/templates/components/custom-wizard-no-access.hbs @@ -1,11 +1,17 @@
{{text}}
- + + {{#if showLoginButton}} +
\ No newline at end of file diff --git a/assets/stylesheets/common/wizard/wizard.scss b/assets/stylesheets/common/wizard/wizard.scss index 4c8f2357..e4a8ef77 100644 --- a/assets/stylesheets/common/wizard/wizard.scss +++ b/assets/stylesheets/common/wizard/wizard.scss @@ -158,7 +158,12 @@ body.custom-wizard { .no-access-gutter { margin-top: 10px; display: flex; - justify-content: flex-end; + justify-content: space-between; + + .return-to-site { + display: flex; + align-items: center; + } } .powered-by-discourse { diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 3e7feba1..15a78ed3 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -5,7 +5,7 @@ en: completed: "You have completed this wizard." not_permitted: "You are not permitted to access this wizard." none: "There is no wizard here." - return_to_site: "Return to {{siteName}}" + return_to_site: "Return to {{siteName}}." requires_login: "You need to be logged in to access this wizard." reset: "Reset this wizard." step_not_permitted: "You're not permitted to view this step." From 7bb26d0d5c710797b520ae1dfdca6dba53d39311 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Tue, 9 Jul 2024 11:26:34 +0200 Subject: [PATCH 4/7] Linting fixes --- .../components/custom-wizard-no-access.js.es6 | 2 +- .../components/wizard-custom-action.js.es6 | 1 - .../components/wizard-mapper-selector.js.es6 | 16 ++++++++++------ .../discourse/components/wizard-mapper.js.es6 | 2 +- .../components/wizard-user-chooser.js.es6 | 7 +++++-- .../discourse/lib/wizard-schema.js.es6 | 4 ++-- .../components/custom-wizard-no-access.hbs | 5 +---- .../components/wizard-custom-action.hbs | 2 +- 8 files changed, 21 insertions(+), 18 deletions(-) diff --git a/assets/javascripts/discourse/components/custom-wizard-no-access.js.es6 b/assets/javascripts/discourse/components/custom-wizard-no-access.js.es6 index 4a7f4889..13ec0611 100644 --- a/assets/javascripts/discourse/components/custom-wizard-no-access.js.es6 +++ b/assets/javascripts/discourse/components/custom-wizard-no-access.js.es6 @@ -36,6 +36,6 @@ export default Component.extend({ showLogin() { cookie("destination_url", getURL(`/w/${this.get("wizardId")}`)); getOwner(this).lookup("route:application").send("showLogin"); - } + }, }, }); diff --git a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 b/assets/javascripts/discourse/components/wizard-custom-action.js.es6 index 1f4c914a..b9329617 100644 --- a/assets/javascripts/discourse/components/wizard-custom-action.js.es6 +++ b/assets/javascripts/discourse/components/wizard-custom-action.js.es6 @@ -5,7 +5,6 @@ import { computed } from "@ember/object"; import UndoChanges from "../mixins/undo-changes"; import Component from "@ember/component"; import I18n from "I18n"; -import { WIZARD_USER } from "./wizard-user-chooser"; export default Component.extend(UndoChanges, { componentType: "action", diff --git a/assets/javascripts/discourse/components/wizard-mapper-selector.js.es6 b/assets/javascripts/discourse/components/wizard-mapper-selector.js.es6 index 5d67b8f7..cfa243e7 100644 --- a/assets/javascripts/discourse/components/wizard-mapper-selector.js.es6 +++ b/assets/javascripts/discourse/components/wizard-mapper-selector.js.es6 @@ -121,9 +121,13 @@ export default Component.extend({ guestGroup: computed("options.guestGroup", "inputType", function () { return this.optionEnabled("guestGroup"); }), - includeMessageableGroups: computed("options.includeMessageableGroups", "inputType", function () { - return this.optionEnabled("includeMessageableGroups"); - }), + includeMessageableGroups: computed( + "options.includeMessageableGroups", + "inputType", + function () { + return this.optionEnabled("includeMessageableGroups"); + } + ), userEnabled: computed("options.userSelection", "inputType", function () { return this.optionEnabled("userSelection"); }), @@ -358,10 +362,10 @@ export default Component.extend({ @discourseComputed("includeMessageableGroups", "options.userLimit") userOptions(includeMessageableGroups, userLimit) { const opts = { - includeMessageableGroups - } + includeMessageableGroups, + }; if (userLimit) { - opts.maximum = userLimit + opts.maximum = userLimit; } return opts; }, diff --git a/assets/javascripts/discourse/components/wizard-mapper.js.es6 b/assets/javascripts/discourse/components/wizard-mapper.js.es6 index 16e2e570..aad6a0e6 100644 --- a/assets/javascripts/discourse/components/wizard-mapper.js.es6 +++ b/assets/javascripts/discourse/components/wizard-mapper.js.es6 @@ -34,7 +34,7 @@ export default Component.extend({ context: options.context || null, guestGroup: options.guestGroup || false, includeMessageableGroups: options.includeMessageableGroups || false, - userLimit: options.userLimit || null + userLimit: options.userLimit || null, }; let inputTypes = ["key", "value", "output"]; diff --git a/assets/javascripts/discourse/components/wizard-user-chooser.js.es6 b/assets/javascripts/discourse/components/wizard-user-chooser.js.es6 index d52c733d..a177a1eb 100644 --- a/assets/javascripts/discourse/components/wizard-user-chooser.js.es6 +++ b/assets/javascripts/discourse/components/wizard-user-chooser.js.es6 @@ -1,4 +1,5 @@ import UserChooserComponent from "select-kit/components/user-chooser"; +import I18n from "I18n"; export const WIZARD_USER = "wizard-user"; @@ -14,7 +15,10 @@ export default UserChooserComponent.extend({ }, modifyNoSelection() { - return this.defaultItem(WIZARD_USER, I18n.t("admin.wizard.action.poster.wizard_user")); + return this.defaultItem( + WIZARD_USER, + I18n.t("admin.wizard.action.poster.wizard_user") + ); }, selectKitOptions: { @@ -28,7 +32,6 @@ export default UserChooserComponent.extend({ return; } return superPromise.then((results) => { - console.log(results) if (!results || results.length === 0) { return; } diff --git a/assets/javascripts/discourse/lib/wizard-schema.js.es6 b/assets/javascripts/discourse/lib/wizard-schema.js.es6 index 0c76fa53..01175ebb 100644 --- a/assets/javascripts/discourse/lib/wizard-schema.js.es6 +++ b/assets/javascripts/discourse/lib/wizard-schema.js.es6 @@ -100,7 +100,7 @@ const action = { custom_fields: null, skip_redirect: null, suppress_notifications: null, - poster: 'wizard-user', + poster: "wizard-user", guest_email: null, add_event: null, add_location: null, @@ -113,7 +113,7 @@ const action = { skip_redirect: null, custom_fields: null, required: null, - poster: 'wizard-user', + poster: "wizard-user", guest_email: null, recipient: null, suppress_notifications: null, diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-no-access.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-no-access.hbs index 5ba51a61..b1dba108 100644 --- a/assets/javascripts/discourse/templates/components/custom-wizard-no-access.hbs +++ b/assets/javascripts/discourse/templates/components/custom-wizard-no-access.hbs @@ -1,9 +1,6 @@
{{text}}
- + {{i18n "wizard.return_to_site" siteName=siteName}} {{#if showLoginButton}} diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs index 1116d79f..bbd0310a 100644 --- a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs @@ -110,7 +110,7 @@ property="poster" onUpdate=(action "mappedFieldUpdated") options=(hash - textSelection='key,value' + textSelection="key,value" wizardFieldSelection=true userSelection="output" outputDefaultSelection="user" From f37d8c94a573d83819fa331cd87bb0c8d015249b Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Tue, 9 Jul 2024 11:30:39 +0200 Subject: [PATCH 5/7] Template linting --- .../discourse/templates/components/custom-wizard-no-access.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/javascripts/discourse/templates/components/custom-wizard-no-access.hbs b/assets/javascripts/discourse/templates/components/custom-wizard-no-access.hbs index b1dba108..30af5d77 100644 --- a/assets/javascripts/discourse/templates/components/custom-wizard-no-access.hbs +++ b/assets/javascripts/discourse/templates/components/custom-wizard-no-access.hbs @@ -1,6 +1,6 @@
{{text}}
- + {{i18n "wizard.return_to_site" siteName=siteName}} {{#if showLoginButton}} From 05388616b589f610eddbcd7401b2699b5fba980d Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Tue, 9 Jul 2024 11:31:02 +0200 Subject: [PATCH 6/7] Update version --- plugin.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin.rb b/plugin.rb index 3358fe97..f70cbc59 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # name: discourse-custom-wizard # about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more. -# version: 2.7.1 +# version: 2.8.0 # authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever, Juan Marcos Gutierrez Ramos # url: https://github.com/paviliondev/discourse-custom-wizard # contact_emails: development@pavilion.tech From c98852f67841685921c598d9e0818bbf812ce601 Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Tue, 9 Jul 2024 11:54:36 +0200 Subject: [PATCH 7/7] Update qunit tests --- .../components/wizard-custom-action.hbs | 84 +++++++++---------- ...dmin-wizards-business-subscription-test.js | 2 +- ...dmin-wizards-standard-subscription-test.js | 4 +- .../admin-wizards-unsubscribed-test.js | 2 +- 4 files changed, 46 insertions(+), 46 deletions(-) diff --git a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs index bbd0310a..9c9898f9 100644 --- a/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs +++ b/assets/javascripts/discourse/templates/components/wizard-custom-action.hbs @@ -98,48 +98,6 @@
{{/if}} - -
-
- -
- -
- {{wizard-mapper - inputs=this.action.poster - property="poster" - onUpdate=(action "mappedFieldUpdated") - options=(hash - textSelection="key,value" - wizardFieldSelection=true - userSelection="output" - outputDefaultSelection="user" - userLimit="1" - context="action" - ) - }} -
-
- -
-
- -
- -
- {{wizard-mapper - inputs=this.action.guest_email - property="guest_email" - onUpdate=(action "mappedFieldUpdated") - options=(hash - textSelection="key,value" - wizardFieldSelection=true - outputPlaceholder="admin.wizard.action.guest_email.placeholder" - context="action" - ) - }} -
-
{{/if}} {{#if publicTopicFields}} @@ -962,6 +920,48 @@ {{/if}} {{#if showPostAdvanced}} +
+
+ +
+ +
+ {{wizard-mapper + inputs=this.action.poster + property="poster" + onUpdate=(action "mappedFieldUpdated") + options=(hash + textSelection="key,value" + wizardFieldSelection=true + userSelection="output" + outputDefaultSelection="user" + userLimit="1" + context="action" + ) + }} +
+
+ +
+
+ +
+ +
+ {{wizard-mapper + inputs=this.action.guest_email + property="guest_email" + onUpdate=(action "mappedFieldUpdated") + options=(hash + textSelection="key,value" + wizardFieldSelection=true + outputPlaceholder="admin.wizard.action.guest_email.placeholder" + context="action" + ) + }} +
+
+
diff --git a/test/javascripts/acceptance/admin-wizards-business-subscription-test.js b/test/javascripts/acceptance/admin-wizards-business-subscription-test.js index e7c2f337..33bbbed9 100644 --- a/test/javascripts/acceptance/admin-wizards-business-subscription-test.js +++ b/test/javascripts/acceptance/admin-wizards-business-subscription-test.js @@ -221,7 +221,7 @@ acceptance("Admin | Custom Wizard Business Subscription", function (needs) { ".admin-wizard-container .wizard-custom-action .setting" ); assert.ok( - listTopicSettings.length === 10, + listTopicSettings.length === 12, "Display all settings of create topic" ); await actionTypeDropdown.expand(); diff --git a/test/javascripts/acceptance/admin-wizards-standard-subscription-test.js b/test/javascripts/acceptance/admin-wizards-standard-subscription-test.js index 7cc05c5c..66aeac1a 100644 --- a/test/javascripts/acceptance/admin-wizards-standard-subscription-test.js +++ b/test/javascripts/acceptance/admin-wizards-standard-subscription-test.js @@ -215,7 +215,7 @@ acceptance("Admin | Custom Wizard Standard Subscription", function (needs) { ".admin-wizard-container .wizard-custom-action .setting" ); assert.ok( - listTopicSettings.length === 10, + listTopicSettings.length === 12, "Display all settings of create topic" ); await actionTypeDropdown.expand(); @@ -224,7 +224,7 @@ acceptance("Admin | Custom Wizard Standard Subscription", function (needs) { ".admin-wizard-container .wizard-custom-action .setting" ); assert.ok( - listTopicSettings.length === 9, + listTopicSettings.length === 11, "Display all settings of send message" ); await actionTypeDropdown.expand(); diff --git a/test/javascripts/acceptance/admin-wizards-unsubscribed-test.js b/test/javascripts/acceptance/admin-wizards-unsubscribed-test.js index 55c456c7..b98b3e1c 100644 --- a/test/javascripts/acceptance/admin-wizards-unsubscribed-test.js +++ b/test/javascripts/acceptance/admin-wizards-unsubscribed-test.js @@ -396,7 +396,7 @@ acceptance("Admin | Custom Wizard Unsubscribed", function (needs) { ".admin-wizard-container .wizard-custom-action .setting" ); assert.ok( - listTopicSettings.length === 10, + listTopicSettings.length === 12, "Display all settings of create topic" ); await actionTypeDropdown.expand();