0
0
Fork 1
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:
Angus McLeod 2023-02-07 12:46:17 +01:00
Ursprung 2c84f019bb
Commit 8f8c6d50c6
23 geänderte Dateien mit 199 neuen und 66 gelöschten Zeilen

Datei anzeigen

@ -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: [

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -24,12 +24,6 @@ class CustomWizard::Subscription
standard: ['*'],
business: ['*'],
community: ['*']
},
allow_guests: {
none: [],
standard: ['*'],
business: ['*'],
community: []
}
},
step: {

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

@ -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
Datei anzeigen

@ -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
Datei anzeigen

@ -0,0 +1,12 @@
{
"permitted": [
{
"type": "assignment",
"output_type": "group",
"output_connector": "set",
"output": [
-1
]
}
]
}

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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

Datei anzeigen

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