Spiegel von
https://github.com/paviliondev/discourse-custom-wizard.git
synchronisiert 2024-11-21 08:50:29 +01:00
Add time groups feature
Dieser Commit ist enthalten in:
Ursprung
95aba3c9c5
Commit
009bb71a24
21 geänderte Dateien mit 258 neuen und 14 gelöschten Zeilen
17
app/controllers/custom_wizard/admin/user.rb
Normale Datei
17
app/controllers/custom_wizard/admin/user.rb
Normale Datei
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
class CustomWizard::UserController < ::Admin::AdminController
|
||||
before_action :ensure_admin
|
||||
requires_plugin "discourse-custom-wizard"
|
||||
|
||||
def clear_redirect
|
||||
user = User.find_by(id: params[:id])
|
||||
|
||||
if user
|
||||
user.custom_fields["redirect_to_wizard"] = nil
|
||||
user.save_custom_fields(true)
|
||||
render json: success_json
|
||||
else
|
||||
render json: failed_json
|
||||
end
|
||||
end
|
||||
end
|
|
@ -78,6 +78,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
|
|||
:resume_on_revisit,
|
||||
:theme_id,
|
||||
permitted: mapped_params,
|
||||
after_time_groups: [],
|
||||
steps: [
|
||||
:id,
|
||||
:index,
|
||||
|
|
|
@ -3,20 +3,32 @@ module Jobs
|
|||
class SetAfterTimeWizard < ::Jobs::Base
|
||||
def execute(args)
|
||||
if SiteSetting.custom_wizard_enabled
|
||||
wizard = CustomWizard::Wizard.create(args[:wizard_id])
|
||||
@wizard = CustomWizard::Wizard.create(args[:wizard_id])
|
||||
|
||||
if wizard && wizard.after_time
|
||||
if @wizard && @wizard.after_time
|
||||
user_ids = []
|
||||
|
||||
User.human_users.each do |user|
|
||||
user_ids.push(user.id) if CustomWizard::Wizard.set_user_redirect(wizard.id, user)
|
||||
target_users.each do |user|
|
||||
user_ids.push(user.id) if CustomWizard::Wizard.set_after_time_redirect(@wizard.id, user)
|
||||
end
|
||||
|
||||
CustomWizard::Template.clear_cache_keys
|
||||
|
||||
MessageBus.publish "/redirect_to_wizard", wizard.id, user_ids: user_ids
|
||||
MessageBus.publish "/redirect_to_wizard", @wizard.id, user_ids: user_ids
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def target_users
|
||||
users = []
|
||||
|
||||
if @wizard.after_time_groups.exists?
|
||||
@wizard.after_time_groups.each { |group| users += group.users }
|
||||
else
|
||||
users = User.human_users
|
||||
end
|
||||
|
||||
users
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<section class="details">
|
||||
<h1>{{i18n "admin.wizard.user.label"}}</h1>
|
||||
|
||||
<div class="display-row">
|
||||
<div class="field">{{i18n "admin.wizard.user.redirect.label"}}</div>
|
||||
<div class="value">
|
||||
{{#if model.redirect_to_wizard}}
|
||||
<LinkTo
|
||||
@route="adminWizardsWizardShow"
|
||||
@model={{dasherize model.redirect_to_wizard}}
|
||||
>
|
||||
{{model.redirect_to_wizard}}
|
||||
</LinkTo>
|
||||
{{else}}
|
||||
—
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="controls">
|
||||
{{#if model.redirect_to_wizard}}
|
||||
<DButton
|
||||
@action={{fn model.clearWizardRedirect model}}
|
||||
@label="admin.wizard.user.redirect.remove_label"
|
||||
@title="admin.wizard.user.redirect.remove_title"
|
||||
/>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
|
@ -12,9 +12,11 @@ import Controller from "@ember/controller";
|
|||
import copyText from "discourse/lib/copy-text";
|
||||
import I18n from "I18n";
|
||||
import { filterValues } from "discourse/plugins/discourse-custom-wizard/discourse/lib/wizard-schema";
|
||||
import { action } from "@ember/object";
|
||||
|
||||
export default Controller.extend({
|
||||
modal: service(),
|
||||
site: service(),
|
||||
hasName: notEmpty("wizard.name"),
|
||||
|
||||
@observes("currentStep")
|
||||
|
@ -91,6 +93,24 @@ export default Controller.extend({
|
|||
return I18n.t(`admin.wizard.error.${errorType}`, errorParams);
|
||||
},
|
||||
|
||||
setAfterTimeGroupIds() {
|
||||
const groups = this.site.groups.filter((g) =>
|
||||
this.wizard.after_time_groups.includes(g.name)
|
||||
);
|
||||
this.setProperties({
|
||||
afterTimeGroupIds: groups.map((g) => g.id),
|
||||
});
|
||||
},
|
||||
|
||||
@action
|
||||
setAfterTimeGroups(groupIds) {
|
||||
const groups = this.site.groups.filter((g) => groupIds.includes(g.id));
|
||||
this.setProperties({
|
||||
afterTimeGroupIds: groups.map((g) => g.id),
|
||||
"wizard.after_time_groups": groups.map((g) => g.name),
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
save() {
|
||||
this.setProperties({
|
||||
|
|
|
@ -2,6 +2,8 @@ import DiscourseURL from "discourse/lib/url";
|
|||
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||
import getUrl from "discourse-common/lib/get-url";
|
||||
import { observes } from "discourse-common/utils/decorators";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
|
||||
export default {
|
||||
name: "custom-wizard-edits",
|
||||
|
@ -105,6 +107,24 @@ export default {
|
|||
route: "adminWizardsWizard",
|
||||
icon: "hat-wizard",
|
||||
});
|
||||
|
||||
if (api.getCurrentUser()?.admin) {
|
||||
api.modifyClass("model:admin-user", {
|
||||
pluginId: "custom-wizard",
|
||||
|
||||
clearWizardRedirect(user) {
|
||||
return ajax(`/admin/users/${user.id}/wizards/clear_redirect`, {
|
||||
type: "PUT",
|
||||
})
|
||||
.then(() => {
|
||||
user.setProperties({
|
||||
redirect_to_wizard: null,
|
||||
});
|
||||
})
|
||||
.catch(popupAjaxError);
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
@ -17,11 +17,13 @@ const wizard = {
|
|||
resume_on_revisit: null,
|
||||
theme_id: null,
|
||||
permitted: null,
|
||||
after_time_groups: null,
|
||||
},
|
||||
mapped: ["permitted"],
|
||||
required: ["id"],
|
||||
dependent: {
|
||||
after_time: "after_time_scheduled",
|
||||
after_time: "after_time_groups",
|
||||
},
|
||||
objectArrays: {
|
||||
step: {
|
||||
|
|
|
@ -47,5 +47,6 @@ export default DiscourseRoute.extend({
|
|||
};
|
||||
|
||||
controller.setProperties(props);
|
||||
controller.setAfterTimeGroupIds();
|
||||
},
|
||||
});
|
||||
|
|
|
@ -162,6 +162,22 @@
|
|||
}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting full">
|
||||
<div class="setting-label">
|
||||
<label>{{i18n "admin.wizard.after_time_groups.label"}}</label>
|
||||
</div>
|
||||
<div class="setting-value">
|
||||
<GroupChooser
|
||||
@content={{this.site.groups}}
|
||||
@value={{this.afterTimeGroupIds}}
|
||||
@onChange={{this.setAfterTimeGroups}}
|
||||
/>
|
||||
<div class="setting-gutter">
|
||||
{{i18n "admin.wizard.after_time_groups.description"}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/wizard-subscription-container}}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -373,11 +373,16 @@ $error: #ef1700;
|
|||
}
|
||||
|
||||
.input .select-kit,
|
||||
> .select-kit {
|
||||
> .select-kit:not(.group-chooser) {
|
||||
max-width: 250px !important;
|
||||
min-width: 250px !important;
|
||||
}
|
||||
|
||||
.group-chooser {
|
||||
max-width: 400px !important;
|
||||
min-width: 400px !important;
|
||||
}
|
||||
|
||||
&.force-final {
|
||||
padding: 1em;
|
||||
background-color: var(--primary-very-low);
|
||||
|
|
|
@ -97,6 +97,9 @@ en:
|
|||
time: "Time"
|
||||
done: "Set Time"
|
||||
clear: "Clear"
|
||||
after_time_groups:
|
||||
label: Time Groups
|
||||
description: Groups directed to wizard after start time.
|
||||
required: "Required"
|
||||
required_label: "Users cannot skip the wizard."
|
||||
prompt_completion: "Prompt"
|
||||
|
@ -587,6 +590,12 @@ en:
|
|||
community:
|
||||
label: Support
|
||||
title: There is a Custom Wizard Community subscription active on this forum.
|
||||
user:
|
||||
label: Wizards
|
||||
redirect:
|
||||
label: Redirect
|
||||
remove_label: Remove
|
||||
remove_title: Remove wizard redirect
|
||||
|
||||
wizard_js:
|
||||
group:
|
||||
|
|
|
@ -52,6 +52,7 @@ en:
|
|||
after_signup: "You can only have one 'after signup' wizard at a time. %{wizard_id} has 'after signup' enabled."
|
||||
after_signup_after_time: "You can't use 'after time' and 'after signup' on the same wizard."
|
||||
after_time: "After time setting is invalid."
|
||||
after_time_group: "After time group does not exist: %{group_name}"
|
||||
liquid_syntax_error: "Liquid syntax error in %{attribute}: %{message}"
|
||||
subscription: "%{type} %{property} usage is not supported on your subscription"
|
||||
not_permitted_for_guests: "%{object_id} is not permitted when guests can access the wizard"
|
||||
|
|
|
@ -46,4 +46,6 @@ Discourse::Application.routes.append do
|
|||
post "admin/wizards/manager/import" => "admin_manager#import"
|
||||
delete "admin/wizards/manager/destroy" => "admin_manager#destroy"
|
||||
end
|
||||
|
||||
put "/admin/users/:id/wizards/clear_redirect" => "custom_wizard/user#clear_redirect"
|
||||
end
|
||||
|
|
|
@ -25,6 +25,12 @@ class CustomWizard::Subscription
|
|||
business: ["*"],
|
||||
community: ["*"],
|
||||
},
|
||||
after_time_groups: {
|
||||
none: [],
|
||||
standard: [],
|
||||
business: ["*"],
|
||||
community: [],
|
||||
},
|
||||
},
|
||||
step: {
|
||||
condition: {
|
||||
|
|
|
@ -176,10 +176,10 @@ class CustomWizard::Template
|
|||
end
|
||||
|
||||
if enqueue_wizard_at
|
||||
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: wizard_id)
|
||||
self.class.clear_user_wizard_redirect(wizard_id, after_time: true)
|
||||
Jobs.enqueue_at(enqueue_wizard_at, :set_after_time_wizard, wizard_id: wizard_id)
|
||||
elsif old_data && old_data[:after_time]
|
||||
clear_user_wizard_redirect(wizard_id, after_time: true)
|
||||
self.class.clear_user_wizard_redirect(wizard_id, after_time: true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -128,6 +128,15 @@ class CustomWizard::TemplateValidator
|
|||
if invalid_time || active_time.blank? || active_time < Time.now.utc
|
||||
errors.add :base, I18n.t("wizard.validation.after_time")
|
||||
end
|
||||
|
||||
group_names = @data[:after_time_groups]
|
||||
if group_names.present?
|
||||
group_names.each do |group_name|
|
||||
unless Group.exists?(name: group_name)
|
||||
errors.add :base, I18n.t("wizard.validation.after_time_group", group_name: group_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def validate_liquid_template(object, type)
|
||||
|
|
|
@ -15,6 +15,7 @@ class CustomWizard::Wizard
|
|||
:multiple_submissions,
|
||||
:after_time,
|
||||
:after_time_scheduled,
|
||||
:after_time_group_names,
|
||||
:after_signup,
|
||||
:required,
|
||||
:prompt_completion,
|
||||
|
@ -58,6 +59,7 @@ class CustomWizard::Wizard
|
|||
@after_signup = cast_bool(attrs["after_signup"])
|
||||
@after_time = cast_bool(attrs["after_time"])
|
||||
@after_time_scheduled = attrs["after_time_scheduled"]
|
||||
@after_time_group_names = attrs["after_time_groups"]
|
||||
@required = cast_bool(attrs["required"])
|
||||
@permitted = attrs["permitted"] || nil
|
||||
@theme_id = attrs["theme_id"]
|
||||
|
@ -251,6 +253,10 @@ class CustomWizard::Wizard
|
|||
permitted?(always_allow_admin: always_allow_admin) && can_submit?
|
||||
end
|
||||
|
||||
def should_redirect?
|
||||
can_access?(always_allow_admin: false) && after_time_target?
|
||||
end
|
||||
|
||||
def reset
|
||||
return nil unless actor_id
|
||||
|
||||
|
@ -329,6 +335,16 @@ class CustomWizard::Wizard
|
|||
end
|
||||
end
|
||||
|
||||
def after_time_groups
|
||||
@after_time_groups ||= Group.where(name: after_time_group_names)
|
||||
end
|
||||
|
||||
def after_time_target?
|
||||
return true if after_time_group_names.blank? || !after_time_groups.exists?
|
||||
return true if after_time_groups.joins(:users).where(users: { username: user.username }).exists?
|
||||
false
|
||||
end
|
||||
|
||||
def self.create(wizard_id, user = nil, guest_id = nil)
|
||||
if template = CustomWizard::Template.find(wizard_id)
|
||||
new(template.to_h, user, guest_id)
|
||||
|
@ -372,6 +388,11 @@ class CustomWizard::Wizard
|
|||
end
|
||||
end
|
||||
|
||||
def self.set_after_time_redirect(wizard_id, user)
|
||||
wizard = self.create(wizard_id, user)
|
||||
set_user_redirect(wizard_id, user) if wizard.after_time_target?
|
||||
end
|
||||
|
||||
def self.set_user_redirect(wizard_id, user)
|
||||
wizard = self.create(wizard_id, user)
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ after_initialize do
|
|||
require_relative "app/controllers/custom_wizard/admin/logs.rb"
|
||||
require_relative "app/controllers/custom_wizard/admin/manager.rb"
|
||||
require_relative "app/controllers/custom_wizard/admin/custom_fields.rb"
|
||||
require_relative "app/controllers/custom_wizard/admin/user.rb"
|
||||
require_relative "app/controllers/custom_wizard/wizard_client.rb"
|
||||
require_relative "app/controllers/custom_wizard/wizard.rb"
|
||||
require_relative "app/controllers/custom_wizard/steps.rb"
|
||||
|
@ -146,6 +147,7 @@ after_initialize do
|
|||
end
|
||||
|
||||
add_to_serializer(:current_user, :redirect_to_wizard) { object.redirect_to_wizard }
|
||||
add_to_serializer(:admin_user_list, :redirect_to_wizard) { object.redirect_to_wizard }
|
||||
|
||||
on(:user_approved) do |user|
|
||||
if wizard = CustomWizard::Wizard.after_signup(user)
|
||||
|
@ -168,7 +170,7 @@ after_initialize do
|
|||
end
|
||||
|
||||
wizard = CustomWizard::Wizard.create(wizard_id, current_user)
|
||||
redirect_to "/w/#{wizard_id.dasherize}" if wizard.can_access?(always_allow_admin: false)
|
||||
redirect_to "/w/#{wizard_id.dasherize}" if wizard.should_redirect?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -154,6 +154,9 @@ describe CustomWizard::Template do
|
|||
expect_not_enqueued_with(job: :set_after_time_wizard) do
|
||||
CustomWizard::Template.save(@after_time_template)
|
||||
end
|
||||
expect(
|
||||
UserCustomField.exists?(name: "redirect_to_wizard", value: @after_time_template[:id]),
|
||||
).to eq(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -47,6 +47,29 @@ describe Jobs::SetAfterTimeWizard do
|
|||
end
|
||||
end
|
||||
|
||||
context "when after_time_groups is set" do
|
||||
fab!(:group1) { Fabricate(:group) }
|
||||
fab!(:group_user) { Fabricate(:group_user, group: group1, user: user2) }
|
||||
|
||||
before do
|
||||
enable_subscription("business")
|
||||
@after_time_template["after_time_groups"] = [group1.name]
|
||||
CustomWizard::Template.save(@after_time_template.as_json)
|
||||
end
|
||||
|
||||
it "only redirects users in the group" do
|
||||
messages =
|
||||
MessageBus.track_publish("/redirect_to_wizard") do
|
||||
described_class.new.execute(wizard_id: "super_mega_fun_wizard")
|
||||
end
|
||||
expect(messages.first.data).to eq("super_mega_fun_wizard")
|
||||
expect(messages.first.user_ids).to match_array([user2.id])
|
||||
expect(
|
||||
UserCustomField.where(name: "redirect_to_wizard", value: "super_mega_fun_wizard").length,
|
||||
).to eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
context "when user has completed the wizard" do
|
||||
before do
|
||||
@after_time_template[:steps].each do |step|
|
||||
|
|
|
@ -78,8 +78,16 @@ describe ApplicationController do
|
|||
end
|
||||
|
||||
context "when time has passed" do
|
||||
it "redirects if time has passed" do
|
||||
def run_job!
|
||||
travel_to Time.now + 4.hours
|
||||
MessageBus.expects(:publish).at_least_once
|
||||
Jobs::SetAfterTimeWizard.new.execute(
|
||||
Jobs::SetAfterTimeWizard.jobs.first["args"].first.symbolize_keys,
|
||||
)
|
||||
end
|
||||
|
||||
it "redirects if time has passed" do
|
||||
run_job!
|
||||
get "/"
|
||||
expect(response).to redirect_to("/w/super-mega-fun-wizard")
|
||||
end
|
||||
|
@ -93,7 +101,7 @@ describe ApplicationController do
|
|||
|
||||
context "when user is in permitted group" do
|
||||
it "redirects user" do
|
||||
travel_to Time.now + 4.hours
|
||||
run_job!
|
||||
get "/"
|
||||
expect(response).to redirect_to("/w/super-mega-fun-wizard")
|
||||
end
|
||||
|
@ -103,7 +111,7 @@ describe ApplicationController do
|
|||
before { Group.find(13).remove(user) }
|
||||
|
||||
it "does not redirect user" do
|
||||
travel_to Time.now + 4.hours
|
||||
run_job!
|
||||
user.trust_level = TrustLevel[2]
|
||||
user.save!
|
||||
get "/"
|
||||
|
@ -111,7 +119,7 @@ describe ApplicationController do
|
|||
end
|
||||
|
||||
it "does not redirect if user is an admin" do
|
||||
travel_to Time.now + 4.hours
|
||||
run_job!
|
||||
user.trust_level = TrustLevel[2]
|
||||
user.admin = true
|
||||
user.save!
|
||||
|
@ -134,11 +142,49 @@ describe ApplicationController do
|
|||
end
|
||||
|
||||
it "does not redirect" do
|
||||
travel_to Time.now + 4.hours
|
||||
run_job!
|
||||
get "/"
|
||||
expect(response).not_to redirect_to("/w/super-mega-fun-wizard")
|
||||
end
|
||||
end
|
||||
|
||||
context "when after_time_groups is set" do
|
||||
fab!(:group)
|
||||
|
||||
before do
|
||||
enable_subscription("business")
|
||||
@template["after_time_groups"] = [group.name]
|
||||
CustomWizard::Template.save(@template.as_json)
|
||||
end
|
||||
|
||||
context "when user is in group" do
|
||||
before { group.add(user) }
|
||||
|
||||
it "redirects user" do
|
||||
run_job!
|
||||
get "/"
|
||||
expect(response).to redirect_to("/w/super-mega-fun-wizard")
|
||||
end
|
||||
end
|
||||
|
||||
context "when user is not in group" do
|
||||
before { group.remove(user) }
|
||||
|
||||
it "does not redirect user" do
|
||||
run_job!
|
||||
get "/"
|
||||
expect(response).to_not redirect_to("/w/super-mega-fun-wizard")
|
||||
end
|
||||
|
||||
it "does not redirect if user is an admin" do
|
||||
run_job!
|
||||
user.admin = true
|
||||
user.save!
|
||||
get "/"
|
||||
expect(response).to_not redirect_to("/w/super-mega-fun-wizard")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Laden …
In neuem Issue referenzieren