Skip to content

Commit 5e5b5e6

Browse files
authored
FIX: Cache valid directs and only allow one type in a template (#176)
* Cache valid directs and only allow one type in a template * Add spec * Bump version * Bump version * Exclude current wizard from other_after_signup
1 parent 5bbb36e commit 5e5b5e6

File tree

14 files changed

+209
-54
lines changed

14 files changed

+209
-54
lines changed

config/locales/server.en.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ en:
4848
validation:
4949
required: "%{property} is required"
5050
conflict: "Wizard with id '%{wizard_id}' already exists"
51-
after_time: "After time setting is invalid"
51+
after_signup: "You can only have one 'after signup' wizard at a time. %{wizard_id} has 'after signup' enabled."
52+
after_signup_after_time: "You can't use 'after time' and 'after signup' on the same wizard."
53+
after_time: "After time setting is invalid."
5254

5355
site_settings:
5456
custom_wizard_enabled: "Enable custom wizards."

controllers/custom_wizard/steps.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def update
5454
updater.result[:redirect_on_complete] = redirect
5555
end
5656

57-
@wizard.final_cleanup!
57+
@wizard.cleanup_on_complete!
5858

5959
result[:final] = true
6060
else

controllers/custom_wizard/wizard.rb

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,17 +60,13 @@ def skip
6060
end
6161

6262
result = success_json
63-
user = current_user
6463

65-
if user && wizard.can_access?
66-
submission = wizard.current_submission
67-
68-
if submission.present? && submission.redirect_to
69-
result.merge!(redirect_to: submission.redirect_to)
64+
if current_user && wizard.can_access?
65+
if redirect_to = wizard.current_submission&.redirect_to
66+
result.merge!(redirect_to: redirect_to)
7067
end
7168

72-
submission.remove if submission.present?
73-
wizard.reset
69+
wizard.cleanup_on_skip!
7470
end
7571

7672
render json: result

coverage/.last_run.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"result": {
3-
"line": 91.83
3+
"line": 92.52
44
}
55
}

extensions/invites_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
module InvitesControllerCustomWizard
33
def path(url)
44
if ::Wizard.user_requires_completion?(@user)
5-
wizard_id = @user.custom_fields['redirect_to_wizard']
5+
wizard_id = @user.redirect_to_wizard
66

77
if wizard_id && url != '/'
88
CustomWizard::Wizard.set_wizard_redirect(@user, wizard_id, url)

jobs/set_after_time_wizard.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ def execute(args)
1414
end
1515
end
1616

17+
CustomWizard::Template.clear_cache_keys
18+
1719
MessageBus.publish "/redirect_to_wizard", wizard.id, user_ids: user_ids
1820
end
1921
end

lib/custom_wizard/template.rb

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
class CustomWizard::Template
44
include HasErrors
55

6+
AFTER_SIGNUP_CACHE_KEY ||= "after_signup_wizard_ids"
7+
AFTER_TIME_CACHE_KEY ||= "after_time_wizard_ids"
8+
69
attr_reader :data,
710
:opts,
811
:steps,
@@ -28,6 +31,8 @@ def save(opts = {})
2831
PluginStore.set(CustomWizard::PLUGIN_NAME, @data[:id], @data)
2932
end
3033

34+
self.class.clear_cache_keys
35+
3136
@data[:id]
3237
end
3338

@@ -53,10 +58,10 @@ def self.remove(wizard_id)
5358

5459
ActiveRecord::Base.transaction do
5560
PluginStore.remove(CustomWizard::PLUGIN_NAME, wizard.id)
56-
clear_user_wizard_redirect(wizard_id)
61+
clear_user_wizard_redirect(wizard_id, after_time: !!wizard.after_time)
5762
end
5863

59-
Jobs.cancel_scheduled_job(:set_after_time_wizard) if wizard.after_time
64+
clear_cache_keys
6065

6166
true
6267
end
@@ -65,9 +70,10 @@ def self.exists?(wizard_id)
6570
PluginStoreRow.exists?(plugin_name: 'custom_wizard', key: wizard_id)
6671
end
6772

68-
def self.list(setting: nil, order: :id)
73+
def self.list(setting: nil, query_str: nil, order: :id)
6974
query = "plugin_name = 'custom_wizard'"
70-
query += "AND (value::json ->> '#{setting}')::boolean IS TRUE" if setting
75+
query += " AND (value::json ->> '#{setting}')::boolean IS TRUE" if setting
76+
query += " #{query_str}" if query_str
7177

7278
PluginStoreRow.where(query).order(order)
7379
.reduce([]) do |result, record|
@@ -85,8 +91,36 @@ def self.list(setting: nil, order: :id)
8591
end
8692
end
8793

88-
def self.clear_user_wizard_redirect(wizard_id)
94+
def self.clear_user_wizard_redirect(wizard_id, after_time: false)
8995
UserCustomField.where(name: 'redirect_to_wizard', value: wizard_id).destroy_all
96+
97+
if after_time
98+
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: wizard_id)
99+
end
100+
end
101+
102+
def self.after_signup_ids
103+
::CustomWizard::Cache.wrap(AFTER_SIGNUP_CACHE_KEY) do
104+
list(setting: 'after_signup').map { |t| t['id'] }
105+
end
106+
end
107+
108+
def self.after_time_ids
109+
::CustomWizard::Cache.wrap(AFTER_TIME_CACHE_KEY) do
110+
list(
111+
setting: 'after_time',
112+
query_str: "AND (value::json ->> 'after_time_scheduled')::timestamp < CURRENT_TIMESTAMP"
113+
).map { |t| t['id'] }
114+
end
115+
end
116+
117+
def self.can_redirect_users?(wizard_id)
118+
after_signup_ids.include?(wizard_id) || after_time_ids.include?(wizard_id)
119+
end
120+
121+
def self.clear_cache_keys
122+
CustomWizard::Cache.new(AFTER_SIGNUP_CACHE_KEY).delete
123+
CustomWizard::Cache.new(AFTER_TIME_CACHE_KEY).delete
90124
end
91125

92126
private
@@ -132,8 +166,7 @@ def schedule_save_jobs
132166
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: wizard_id)
133167
Jobs.enqueue_at(enqueue_wizard_at, :set_after_time_wizard, wizard_id: wizard_id)
134168
elsif old_data && old_data[:after_time]
135-
Jobs.cancel_scheduled_job(:set_after_time_wizard, wizard_id: wizard_id)
136-
self.class.clear_user_wizard_redirect(wizard_id)
169+
clear_user_wizard_redirect(wizard_id, after_time: true)
137170
end
138171
end
139172
end

lib/custom_wizard/validators/template.rb

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@ def perform
1313

1414
check_id(data, :wizard)
1515
check_required(data, :wizard)
16+
validate_after_signup
1617
validate_after_time
1718

19+
return false if errors.any?
20+
1821
data[:steps].each do |step|
1922
check_required(step, :step)
2023

@@ -31,11 +34,7 @@ def perform
3134
end
3235
end
3336

34-
if errors.any?
35-
false
36-
else
37-
true
38-
end
37+
!errors.any?
3938
end
4039

4140
def self.required
@@ -63,8 +62,24 @@ def check_id(object, type)
6362
end
6463
end
6564

65+
def validate_after_signup
66+
return unless ActiveRecord::Type::Boolean.new.cast(@data[:after_signup])
67+
68+
other_after_signup = CustomWizard::Template.list(setting: 'after_signup')
69+
.select { |template| template['id'] != @data[:id] }
70+
71+
if other_after_signup.any?
72+
errors.add :base, I18n.t("wizard.validation.after_signup", wizard_id: other_after_signup.first['id'])
73+
end
74+
end
75+
6676
def validate_after_time
67-
return unless @data[:after_time]
77+
return unless ActiveRecord::Type::Boolean.new.cast(@data[:after_time])
78+
79+
if ActiveRecord::Type::Boolean.new.cast(@data[:after_signup])
80+
errors.add :base, I18n.t("wizard.validation.after_signup_after_time")
81+
return
82+
end
6883

6984
wizard = CustomWizard::Wizard.create(@data[:id]) if !@opts[:create]
7085
current_time = wizard.present? ? wizard.after_time_scheduled : nil

lib/custom_wizard/wizard.rb

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -288,11 +288,8 @@ def current_submission
288288
end
289289
end
290290

291-
def final_cleanup!
292-
if id == user.custom_fields['redirect_to_wizard']
293-
user.custom_fields.delete('redirect_to_wizard')
294-
user.save_custom_fields(true)
295-
end
291+
def cleanup_on_complete!
292+
remove_user_redirect
296293

297294
if current_submission.present?
298295
current_submission.submitted_at = Time.now.iso8601
@@ -302,6 +299,23 @@ def final_cleanup!
302299
update!
303300
end
304301

302+
def cleanup_on_skip!
303+
remove_user_redirect
304+
305+
if current_submission.present?
306+
current_submission.remove
307+
end
308+
309+
reset
310+
end
311+
312+
def remove_user_redirect
313+
if id == user.redirect_to_wizard
314+
user.custom_fields.delete('redirect_to_wizard')
315+
user.save_custom_fields(true)
316+
end
317+
end
318+
305319
def self.create(wizard_id, user = nil)
306320
if template = CustomWizard::Template.find(wizard_id)
307321
new(template.to_h, user)

plugin.rb

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# frozen_string_literal: true
22
# name: discourse-custom-wizard
33
# about: Create custom wizards
4-
# version: 1.16.4
4+
# version: 1.16.5
55
# authors: Angus McLeod
66
# url: https://github.com/paviliondev/discourse-custom-wizard
77
# contact emails: angus@thepavilion.io
@@ -149,16 +149,24 @@ def process_require_tree_discourse_directive(path = ".")
149149
!!custom_redirect
150150
end
151151

152+
add_to_class(:user, :redirect_to_wizard) do
153+
if custom_fields['redirect_to_wizard'].present?
154+
custom_fields['redirect_to_wizard']
155+
else
156+
nil
157+
end
158+
end
159+
152160
add_to_class(:users_controller, :wizard_path) do
153-
if custom_wizard_redirect = current_user.custom_fields['redirect_to_wizard']
161+
if custom_wizard_redirect = current_user.redirect_to_wizard
154162
"#{Discourse.base_url}/w/#{custom_wizard_redirect.dasherize}"
155163
else
156164
"#{Discourse.base_url}/wizard"
157165
end
158166
end
159167

160168
add_to_serializer(:current_user, :redirect_to_wizard) do
161-
object.custom_fields['redirect_to_wizard']
169+
object.redirect_to_wizard
162170
end
163171

164172
on(:user_approved) do |user|
@@ -168,15 +176,19 @@ def process_require_tree_discourse_directive(path = ".")
168176
end
169177

170178
add_to_class(:application_controller, :redirect_to_wizard_if_required) do
171-
wizard_id = current_user.custom_fields['redirect_to_wizard']
172179
@excluded_routes ||= SiteSetting.wizard_redirect_exclude_paths.split('|') + ['/w/']
173180
url = request.referer || request.original_url
181+
excluded_route = @excluded_routes.any? { |str| /#{str}/ =~ url }
182+
not_api = request.format === 'text/html'
183+
184+
if not_api && !excluded_route
185+
wizard_id = current_user.redirect_to_wizard
186+
187+
if CustomWizard::Template.can_redirect_users?(wizard_id)
188+
if url !~ /\/w\// && url !~ /\/invites\//
189+
CustomWizard::Wizard.set_wizard_redirect(current_user, wizard_id, url)
190+
end
174191

175-
if request.format === 'text/html' && !@excluded_routes.any? { |str| /#{str}/ =~ url } && wizard_id
176-
if request.referer !~ /\/w\// && request.referer !~ /\/invites\//
177-
CustomWizard::Wizard.set_wizard_redirect(current_user, wizard_id, request.referer)
178-
end
179-
if CustomWizard::Template.exists?(wizard_id)
180192
redirect_to "/w/#{wizard_id.dasherize}"
181193
end
182194
end

0 commit comments

Comments
 (0)