Spiegel von
https://github.com/paviliondev/discourse-custom-wizard.git
synchronisiert 2024-11-22 09:20:29 +01:00
move guest toggle to permitted attribute
Dieser Commit ist enthalten in:
Ursprung
2c84f019bb
Commit
8f8c6d50c6
23 geänderte Dateien mit 199 neuen und 66 gelöschten Zeilen
|
@ -80,7 +80,6 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
|
|||
:prompt_completion,
|
||||
:restart_on_revisit,
|
||||
:resume_on_revisit,
|
||||
:allow_guests,
|
||||
:theme_id,
|
||||
permitted: mapped_params,
|
||||
steps: [
|
||||
|
|
|
@ -9,8 +9,7 @@ class CustomWizard::WizardSerializer < CustomWizard::BasicWizardSerializer
|
|||
:completed,
|
||||
:required,
|
||||
:permitted,
|
||||
:resume_on_revisit,
|
||||
:allow_guests
|
||||
:resume_on_revisit
|
||||
|
||||
has_many :steps, serializer: ::CustomWizard::StepSerializer, embed: :objects
|
||||
has_one :user, serializer: ::BasicUserSerializer, embed: :objects
|
||||
|
|
|
@ -116,6 +116,9 @@ export default Component.extend({
|
|||
groupEnabled: computed("options.groupSelection", "inputType", function () {
|
||||
return this.optionEnabled("groupSelection");
|
||||
}),
|
||||
guestGroup: computed("options.guestGroup", "inputType", function () {
|
||||
return this.optionEnabled("guestGroup");
|
||||
}),
|
||||
userEnabled: computed("options.userSelection", "inputType", function () {
|
||||
return this.optionEnabled("userSelection");
|
||||
}),
|
||||
|
@ -126,7 +129,26 @@ export default Component.extend({
|
|||
return this.connector === "is";
|
||||
}),
|
||||
|
||||
groups: alias("site.groups"),
|
||||
@discourseComputed("site.groups", "guestGroup")
|
||||
groups(groups, guestGroup) {
|
||||
let result = groups;
|
||||
if (!guestGroup) {
|
||||
return result;
|
||||
}
|
||||
|
||||
let guestIndex;
|
||||
result.forEach((r, index) => {
|
||||
if (r.id === 0) {
|
||||
r.name = I18n.t("admin.wizard.selector.label.users");
|
||||
guestIndex = index;
|
||||
}
|
||||
});
|
||||
result.splice(guestIndex, 0, {
|
||||
id: -1,
|
||||
name: I18n.t("admin.wizard.selector.label.guests"),
|
||||
});
|
||||
return result;
|
||||
},
|
||||
categories: alias("site.categories"),
|
||||
showComboBox: or(
|
||||
"showWizardField",
|
||||
|
|
|
@ -32,6 +32,7 @@ export default Component.extend({
|
|||
pairConnector: options.pairConnector || null,
|
||||
outputConnector: options.outputConnector || null,
|
||||
context: options.context || null,
|
||||
guestGroup: options.guestGroup || false,
|
||||
};
|
||||
|
||||
let inputTypes = ["key", "value", "output"];
|
||||
|
|
|
@ -56,7 +56,7 @@ export default SingleSelectComponent.extend(Subscription, {
|
|||
return attributes;
|
||||
},
|
||||
|
||||
@discourseComputed("feature", "attribute", "wizard.allow_guests")
|
||||
@discourseComputed("feature", "attribute", "wizard.allowGuests")
|
||||
content(feature, attribute, allowGuests) {
|
||||
return this.contentList(feature, attribute, allowGuests)
|
||||
.map((value) => {
|
||||
|
|
|
@ -15,7 +15,6 @@ const wizard = {
|
|||
prompt_completion: null,
|
||||
restart_on_revisit: null,
|
||||
resume_on_revisit: null,
|
||||
allow_guests: null,
|
||||
theme_id: null,
|
||||
permitted: null,
|
||||
},
|
||||
|
|
|
@ -5,8 +5,16 @@ import wizardSchema from "../lib/wizard-schema";
|
|||
import { Promise } from "rsvp";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
|
||||
const GUEST_GROUP_ID = -1;
|
||||
|
||||
const CustomWizardAdmin = EmberObject.extend({
|
||||
@discourseComputed("permitted.@each")
|
||||
allowGuests(permitted) {
|
||||
return permitted.filter((p) => p.output === GUEST_GROUP_ID).length;
|
||||
},
|
||||
|
||||
save(opts) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let wizard = this.buildJson(this, "wizard");
|
||||
|
|
|
@ -4,13 +4,7 @@ import Route from "@ember/routing/route";
|
|||
export default Route.extend({
|
||||
beforeModel() {
|
||||
const wizard = getCachedWizard();
|
||||
if (
|
||||
wizard &&
|
||||
(wizard.user || wizard.allow_guests) &&
|
||||
wizard.permitted &&
|
||||
!wizard.completed &&
|
||||
wizard.start
|
||||
) {
|
||||
if (wizard && wizard.permitted && !wizard.completed && wizard.start) {
|
||||
this.replaceWith("customWizardStep", wizard.start);
|
||||
}
|
||||
},
|
||||
|
@ -26,7 +20,7 @@ export default Route.extend({
|
|||
const wizardId = model.get("id");
|
||||
const user = model.get("user");
|
||||
const name = model.get("name");
|
||||
const requiresLogin = !user && !model.get("allow_guests");
|
||||
const requiresLogin = !user && !permitted;
|
||||
const notPermitted = !permitted;
|
||||
|
||||
const props = {
|
||||
|
|
|
@ -7,12 +7,7 @@ export default Route.extend({
|
|||
const wizard = getCachedWizard();
|
||||
this.set("wizard", wizard);
|
||||
|
||||
if (
|
||||
!wizard ||
|
||||
(!wizard.user && !wizard.allow_guests) ||
|
||||
!wizard.permitted ||
|
||||
wizard.completed
|
||||
) {
|
||||
if (!wizard || !wizard.permitted || wizard.completed) {
|
||||
this.replaceWith("customWizard");
|
||||
}
|
||||
},
|
||||
|
|
|
@ -140,22 +140,13 @@
|
|||
context="wizard"
|
||||
inputTypes="assignment,validation"
|
||||
groupSelection="output"
|
||||
guestGroup=true
|
||||
userFieldSelection="key"
|
||||
textSelection="value"
|
||||
inputConnector="and"
|
||||
)}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting full">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.allow_guests"}}</label>
|
||||
</div>
|
||||
<div class="setting-value">
|
||||
{{input type="checkbox" checked=wizard.allow_guests}}
|
||||
<span>{{i18n "admin.wizard.allow_guests_label"}}</span>
|
||||
</div>
|
||||
</div>
|
||||
{{/wizard-subscription-container}}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -105,8 +105,6 @@ en:
|
|||
restart_on_revisit_label: "Clear submissions on each visit."
|
||||
resume_on_revisit: "Resume"
|
||||
resume_on_revisit_label: "Ask the user if they want to resume on each visit."
|
||||
allow_guests: "Guests"
|
||||
allow_guests_label: "Allow guests to use the wizard (disables user-specific features)."
|
||||
theme_id: "Theme"
|
||||
no_theme: "Select a Theme (optional)"
|
||||
save: "Save Changes"
|
||||
|
@ -219,6 +217,8 @@ en:
|
|||
list: "list"
|
||||
custom_field: "custom field"
|
||||
value: "value"
|
||||
users: "users"
|
||||
guests: "users and guests"
|
||||
|
||||
placeholder:
|
||||
text: "Enter text"
|
||||
|
|
|
@ -54,7 +54,7 @@ en:
|
|||
after_time: "After time setting is invalid."
|
||||
liquid_syntax_error: "Liquid syntax error in %{attribute}: %{message}"
|
||||
subscription: "%{type} %{property} is subscription only"
|
||||
allow_guests: "%{object_id} is not permitted when allow_guests is enabled"
|
||||
not_permitted_for_guests: "%{object_id} is not permitted when guests can access the wizard"
|
||||
|
||||
site_settings:
|
||||
custom_wizard_enabled: "Enable custom wizards."
|
||||
|
|
|
@ -136,7 +136,7 @@ class CustomWizard::Action
|
|||
|
||||
params[:archetype] = Archetype.private_message
|
||||
|
||||
poster = @wizard.allow_guests ? Discourse.system_user : user
|
||||
poster = user || Discourse.system_user
|
||||
creator = PostCreator.new(poster, params)
|
||||
post = creator.create
|
||||
|
||||
|
|
|
@ -24,12 +24,6 @@ class CustomWizard::Subscription
|
|||
standard: ['*'],
|
||||
business: ['*'],
|
||||
community: ['*']
|
||||
},
|
||||
allow_guests: {
|
||||
none: [],
|
||||
standard: ['*'],
|
||||
business: ['*'],
|
||||
community: []
|
||||
}
|
||||
},
|
||||
step: {
|
||||
|
|
|
@ -82,8 +82,12 @@ class CustomWizard::TemplateValidator
|
|||
end
|
||||
|
||||
def validate_action(action)
|
||||
if @data[:allow_guests] && CustomWizard::Action::REQUIRES_USER.include?(action[:type])
|
||||
errors.add :base, I18n.t("wizard.validation.allow_guests", object_id: action[:id])
|
||||
guests_permitted = @data[:permitted] && @data[:permitted].any? do |m|
|
||||
m[:output] === CustomWizard::Wizard::GUEST_GROUP_ID
|
||||
end
|
||||
|
||||
if guests_permitted && CustomWizard::Action::REQUIRES_USER.include?(action[:type])
|
||||
errors.add :base, I18n.t("wizard.validation.not_permitted_for_guests", object_id: action[:id])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ class CustomWizard::Wizard
|
|||
:prompt_completion,
|
||||
:restart_on_revisit,
|
||||
:resume_on_revisit,
|
||||
:allow_guests,
|
||||
:permitted,
|
||||
:steps,
|
||||
:step_ids,
|
||||
|
@ -37,6 +36,7 @@ class CustomWizard::Wizard
|
|||
attr_reader :all_step_ids
|
||||
|
||||
GUEST_ID_PREFIX ||= "guest"
|
||||
GUEST_GROUP_ID = -1
|
||||
|
||||
def initialize(attrs = {}, user = nil, guest_id = nil)
|
||||
if user
|
||||
|
@ -55,7 +55,6 @@ class CustomWizard::Wizard
|
|||
@prompt_completion = cast_bool(attrs['prompt_completion'])
|
||||
@restart_on_revisit = cast_bool(attrs['restart_on_revisit'])
|
||||
@resume_on_revisit = cast_bool(attrs['resume_on_revisit'])
|
||||
@allow_guests = cast_bool(attrs['allow_guests'])
|
||||
@after_signup = cast_bool(attrs['after_signup'])
|
||||
@after_time = cast_bool(attrs['after_time'])
|
||||
@after_time_scheduled = attrs['after_time_scheduled']
|
||||
|
@ -212,9 +211,8 @@ class CustomWizard::Wizard
|
|||
|
||||
def permitted?
|
||||
return nil unless actor_id
|
||||
return true if allow_guests
|
||||
return false unless user
|
||||
return true if user.admin? || permitted.blank?
|
||||
return true if user && (user.admin? || permitted.blank?)
|
||||
return false if !user && permitted.blank?
|
||||
|
||||
mapper = CustomWizard::Mapper.new(
|
||||
inputs: permitted,
|
||||
|
@ -228,22 +226,22 @@ class CustomWizard::Wizard
|
|||
return true if mapper.blank?
|
||||
|
||||
mapper.all? do |m|
|
||||
if m[:type] === 'assignment'
|
||||
[*m[:result]].include?(Group::AUTO_GROUPS[:everyone]) ||
|
||||
GroupUser.exists?(group_id: m[:result], user_id: user.id)
|
||||
elsif m[:type] === 'validation'
|
||||
m[:result]
|
||||
if !user
|
||||
m[:type] === 'assignment' && [*m[:result]].include?(GUEST_GROUP_ID)
|
||||
else
|
||||
true
|
||||
if m[:type] === 'assignment'
|
||||
[*m[:result]].include?(Group::AUTO_GROUPS[:everyone]) ||
|
||||
GroupUser.exists?(group_id: m[:result], user_id: user.id)
|
||||
elsif m[:type] === 'validation'
|
||||
m[:result]
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def can_access?
|
||||
return nil unless actor_id
|
||||
return true if allow_guests
|
||||
return false unless user
|
||||
return true if user.admin
|
||||
permitted? && (multiple_submissions || !completed?)
|
||||
end
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ describe CustomWizard::Action do
|
|||
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)
|
||||
|
@ -302,8 +303,8 @@ describe CustomWizard::Action do
|
|||
expect(post.exists?).to eq(true)
|
||||
end
|
||||
|
||||
it "send_message works with allow_guests enabled" do
|
||||
wizard_template["allow_guests"] = true
|
||||
it "send_message works with guests are permitted" do
|
||||
wizard_template["permitted"] = guests_permitted["permitted"]
|
||||
wizard_template.delete("actions")
|
||||
wizard_template['actions'] = [send_message]
|
||||
update_template(wizard_template)
|
||||
|
|
12
spec/fixtures/actions/route_to.json
gevendort
Normale Datei
12
spec/fixtures/actions/route_to.json
gevendort
Normale Datei
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"id": "route_to",
|
||||
"type": "route_to",
|
||||
"url": [
|
||||
{
|
||||
"type": "assignment",
|
||||
"output": "https://google.com",
|
||||
"output_type": "text",
|
||||
"output_connector": "set"
|
||||
}
|
||||
]
|
||||
}
|
12
spec/fixtures/wizard/guests_permitted.json
gevendort
Normale Datei
12
spec/fixtures/wizard/guests_permitted.json
gevendort
Normale Datei
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"permitted": [
|
||||
{
|
||||
"type": "assignment",
|
||||
"output_type": "group",
|
||||
"output_connector": "set",
|
||||
"output": [
|
||||
-1
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -7,11 +7,21 @@ describe CustomWizard::StepsController do
|
|||
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") }
|
||||
let(:route_to_template) { get_wizard_fixture("actions/route_to") }
|
||||
let(:guests_permitted) { get_wizard_fixture("wizard/guests_permitted") }
|
||||
|
||||
before do
|
||||
CustomWizard::Template.save(wizard_template, skip_jobs: true)
|
||||
end
|
||||
|
||||
def guest_template
|
||||
temp = wizard_template.dup
|
||||
temp["permitted"] = guests_permitted["permitted"]
|
||||
temp.delete("actions")
|
||||
temp["actions"] = [route_to_template]
|
||||
temp
|
||||
end
|
||||
|
||||
context "with guest" do
|
||||
it "does not perform a step update" do
|
||||
put '/w/super-mega-fun-wizard/steps/step_1.json', params: {
|
||||
|
@ -22,13 +32,10 @@ describe CustomWizard::StepsController do
|
|||
expect(response.status).to eq(403)
|
||||
end
|
||||
|
||||
context "with allow_guests enabled" do
|
||||
context "with guests permitted" do
|
||||
before do
|
||||
enable_subscription("standard")
|
||||
new_template = wizard_template.dup
|
||||
new_template["allow_guests"] = true
|
||||
new_template.delete("actions")
|
||||
result = CustomWizard::Template.save(new_template, skip_jobs: true)
|
||||
result = CustomWizard::Template.save(guest_template, skip_jobs: true)
|
||||
end
|
||||
|
||||
it "performs a step update" do
|
||||
|
@ -44,6 +51,62 @@ describe CustomWizard::StepsController do
|
|||
wizard = CustomWizard::Wizard.create(wizard_id, nil, cookies[:custom_wizard_guest_id])
|
||||
expect(wizard.current_submission.fields['step_1_field_1']).to eq("Text input")
|
||||
end
|
||||
|
||||
context "raises an error" do
|
||||
it "when the wizard doesnt exist" do
|
||||
put '/w/not-super-mega-fun-wizard/steps/step_1.json'
|
||||
expect(response.status).to eq(400)
|
||||
end
|
||||
|
||||
it "when the user cant access the wizard" do
|
||||
enable_subscription("standard")
|
||||
new_template = guest_template.dup
|
||||
new_template["permitted"] = permitted_json["permitted"]
|
||||
CustomWizard::Template.save(new_template, skip_jobs: true)
|
||||
|
||||
put '/w/super-mega-fun-wizard/steps/step_1.json'
|
||||
expect(response.status).to eq(403)
|
||||
end
|
||||
|
||||
it "when the step doesnt exist" do
|
||||
put '/w/super-mega-fun-wizard/steps/step_10.json'
|
||||
expect(response.status).to eq(400)
|
||||
end
|
||||
end
|
||||
|
||||
it "works if the step has no fields" do
|
||||
put '/w/super-mega-fun-wizard/steps/step_1.json'
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body['wizard']['start']).to eq("step_2")
|
||||
end
|
||||
|
||||
it "returns an updated wizard when condition passes" do
|
||||
new_template = guest_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 will pass"
|
||||
}
|
||||
}
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body['wizard']['start']).to eq("step_2")
|
||||
end
|
||||
|
||||
it "runs completion actions if guest has completed wizard" do
|
||||
new_template = guest_template.dup
|
||||
|
||||
## route_to action
|
||||
new_template['actions'].last['run_after'] = 'wizard_completion'
|
||||
CustomWizard::Template.save(new_template, skip_jobs: true)
|
||||
|
||||
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
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -122,4 +122,44 @@ acceptance("Wizard | Guest access", function (needs) {
|
|||
await visit("/w/wizard");
|
||||
assert.ok(query(".wizard-column"), true);
|
||||
});
|
||||
|
||||
test("Applies the wizard body class", async function (assert) {
|
||||
await visit("/w/wizard");
|
||||
assert.ok($("body.custom-wizard").length);
|
||||
});
|
||||
|
||||
test("Applies the body background color", async function (assert) {
|
||||
await visit("/w/wizard");
|
||||
assert.ok($("body")[0].style.background);
|
||||
});
|
||||
|
||||
test("Renders the wizard form", async function (assert) {
|
||||
await visit("/w/wizard");
|
||||
assert.ok(exists(".wizard-column-contents .wizard-step"), true);
|
||||
assert.ok(exists(".wizard-footer img"), true);
|
||||
});
|
||||
|
||||
test("Renders the first step", async function (assert) {
|
||||
await visit("/w/wizard");
|
||||
assert.strictEqual(
|
||||
query(".wizard-step-title p").textContent.trim(),
|
||||
"Text"
|
||||
);
|
||||
assert.strictEqual(
|
||||
query(".wizard-step-description p").textContent.trim(),
|
||||
"Text inputs!"
|
||||
);
|
||||
assert.strictEqual(
|
||||
query(".wizard-step-description p").textContent.trim(),
|
||||
"Text inputs!"
|
||||
);
|
||||
assert.strictEqual(count(".wizard-step-form .wizard-field"), 6);
|
||||
assert.ok(exists(".wizard-step-footer .wizard-progress"), true);
|
||||
assert.ok(exists(".wizard-step-footer .wizard-buttons"), true);
|
||||
});
|
||||
|
||||
test("Removes the wizard body class when navigating away", async function (assert) {
|
||||
await visit("/");
|
||||
assert.strictEqual($("body.custom-wizard").length, 0);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -6,7 +6,7 @@ export default {
|
|||
submission_last_updated_at: "2022-03-15T21:11:01+01:00",
|
||||
theme_id: 2,
|
||||
required: false,
|
||||
permitted: true,
|
||||
permitted: false,
|
||||
uncategorized_category_id: 1,
|
||||
categories: [],
|
||||
subscribed: false,
|
||||
|
|
|
@ -7,9 +7,10 @@ import { cloneJSON } from "discourse-common/lib/object";
|
|||
|
||||
const wizardNoUser = cloneJSON(wizardJson);
|
||||
const wizardGuest = cloneJSON(wizardJson);
|
||||
wizardGuest.allow_guests = true;
|
||||
wizardGuest.permitted = true;
|
||||
const wizard = cloneJSON(wizardJson);
|
||||
wizard.user = cloneJSON(userJson);
|
||||
wizard.permitted = true;
|
||||
|
||||
const wizardNotPermitted = cloneJSON(wizard);
|
||||
wizardNotPermitted.permitted = false;
|
||||
|
|
Laden …
In neuem Issue referenzieren