0
0
Fork 1
Spiegel von https://github.com/paviliondev/discourse-custom-wizard.git synchronisiert 2024-11-21 17:00:29 +01:00

Add poster and guest_email to topic and message creation && allow guests to create_topic

Dieser Commit ist enthalten in:
Angus McLeod 2024-07-09 11:23:57 +02:00
Ursprung 441ad49bf6
Commit cff8f9f427
15 geänderte Dateien mit 336 neuen und 55 gelöschten Zeilen

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -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 };
});
});
},
});

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -98,6 +98,48 @@
</div>
</div>
{{/if}}
<div class="setting full field-mapper-setting">
<div class="setting-label">
<label>{{i18n "admin.wizard.action.poster.label"}}</label>
</div>
<div class="setting-value">
{{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"
)
}}
</div>
</div>
<div class="setting full field-mapper-setting">
<div class="setting-label">
<label>{{i18n "admin.wizard.action.guest_email.label"}}</label>
</div>
<div class="setting-value">
{{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"
)
}}
</div>
</div>
{{/if}}
{{#if publicTopicFields}}
@ -217,6 +259,7 @@
userSelection="output"
outputDefaultSelection="user"
context="action"
includeMessageableGroups="true"
)
}}
</div>

Datei anzeigen

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

Datei anzeigen

@ -0,0 +1,20 @@
{{#if this.item.isUser}}
{{avatar this.item imageSize="tiny"}}
<div>
<span class="identifier">{{format-username this.item.id}}</span>
<span class="name">{{this.item.name}}</span>
</div>
{{#if (and this.item.showUserStatus this.item.status)}}
<UserStatusMessage @status={{this.item.status}} @showDescription={{true}} />
{{/if}}
{{decorate-username-selector this.item.id}}
{{else if this.item.isGroup}}
{{d-icon "users"}}
<div>
<span class="identifier">{{this.item.id}}</span>
<span class="name">{{this.item.full_name}}</span>
</div>
{{else}}
{{d-icon "envelope"}}
<span class="identifier">{{this.item.id}}</span>
{{/if}}

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -31,7 +31,6 @@ class CustomWizard::Field
:step
REQUIRES_USER = %w[
composer
upload
]

Datei anzeigen

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

Datei anzeigen

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