mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 02:11:08 -06:00
FIX: Don’t list values from disabled plugins
Currently, when a plugin registers a new reviewable type or extends a list method (through `register_reviewble_type` and `extend_list_method` respectively), the new array is statically computed and always returns the same value. It will continue to return the same value even if the plugin is disabled (it can be a problem in a multisite env too). To address this issue, this patch changes how `extend_list_method` works. It’s now using `DiscoursePluginRegistry.define_filtered_register` to create a register on the fly and store the extra values from various plugins. It then combines the original values with the ones from the registry. The registry is already aware of disabled plugins, so when a plugin is disabled, its registered values won’t be returned.
This commit is contained in:
parent
66878a9e80
commit
5ec227334a
@ -66,14 +66,11 @@ class Reviewable < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.valid_type?(type)
|
def self.valid_type?(type)
|
||||||
return false if Reviewable.types.exclude?(type)
|
type.to_s.safe_constantize.in?(types)
|
||||||
type.constantize <= Reviewable
|
|
||||||
rescue NameError
|
|
||||||
false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.types
|
def self.types
|
||||||
%w[ReviewableFlaggedPost ReviewableQueuedPost ReviewableUser ReviewablePost]
|
[ReviewableFlaggedPost, ReviewableQueuedPost, ReviewableUser, ReviewablePost]
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.custom_filters
|
def self.custom_filters
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
# A class that handles interaction between a plugin and the Discourse App.
|
# A class that handles interaction between a plugin and the Discourse App.
|
||||||
#
|
#
|
||||||
class DiscoursePluginRegistry
|
class DiscoursePluginRegistry
|
||||||
|
@@register_names = Set.new
|
||||||
|
|
||||||
# Plugins often need to be able to register additional handlers, data, or
|
# Plugins often need to be able to register additional handlers, data, or
|
||||||
# classes that will be used by core classes. This should be used if you
|
# classes that will be used by core classes. This should be used if you
|
||||||
# need to control which type the registry is, and if it doesn't need to
|
# need to control which type the registry is, and if it doesn't need to
|
||||||
@ -15,7 +17,7 @@ class DiscoursePluginRegistry
|
|||||||
# - Defines instance method as a shortcut to the singleton method
|
# - Defines instance method as a shortcut to the singleton method
|
||||||
# - Automatically deletes the register on registry.reset!
|
# - Automatically deletes the register on registry.reset!
|
||||||
def self.define_register(register_name, type)
|
def self.define_register(register_name, type)
|
||||||
@@register_names ||= Set.new
|
return if respond_to?(register_name)
|
||||||
@@register_names << register_name
|
@@register_names << register_name
|
||||||
|
|
||||||
define_singleton_method(register_name) do
|
define_singleton_method(register_name) do
|
||||||
@ -36,13 +38,13 @@ class DiscoursePluginRegistry
|
|||||||
# - Defines instance method as a shortcut to the singleton method
|
# - Defines instance method as a shortcut to the singleton method
|
||||||
# - Automatically deletes the register on registry.reset!
|
# - Automatically deletes the register on registry.reset!
|
||||||
def self.define_filtered_register(register_name)
|
def self.define_filtered_register(register_name)
|
||||||
|
return if respond_to?(register_name)
|
||||||
define_register(register_name, Array)
|
define_register(register_name, Array)
|
||||||
|
|
||||||
singleton_class.alias_method :"_raw_#{register_name}", :"#{register_name}"
|
singleton_class.alias_method :"_raw_#{register_name}", :"#{register_name}"
|
||||||
|
|
||||||
define_singleton_method(register_name) do
|
define_singleton_method(register_name) do
|
||||||
unfiltered = public_send(:"_raw_#{register_name}")
|
public_send(:"_raw_#{register_name}").filter_map { |h| h[:value] if h[:plugin].enabled? }.uniq
|
||||||
unfiltered.filter { |v| v[:plugin].enabled? }.map { |v| v[:value] }.uniq
|
|
||||||
end
|
end
|
||||||
|
|
||||||
define_singleton_method("register_#{register_name.to_s.singularize}") do |value, plugin|
|
define_singleton_method("register_#{register_name.to_s.singularize}") do |value, plugin|
|
||||||
|
@ -831,14 +831,28 @@ class Plugin::Instance
|
|||||||
end
|
end
|
||||||
|
|
||||||
def register_reviewable_type(reviewable_type_class)
|
def register_reviewable_type(reviewable_type_class)
|
||||||
extend_list_method Reviewable, :types, [reviewable_type_class.name]
|
return unless reviewable_type_class < Reviewable
|
||||||
|
extend_list_method(Reviewable, :types, reviewable_type_class)
|
||||||
end
|
end
|
||||||
|
|
||||||
def extend_list_method(klass, method, new_attributes)
|
def extend_list_method(klass, method, new_attributes)
|
||||||
current_list = klass.public_send(method)
|
register_name = [klass, method].join("_").underscore
|
||||||
current_list.concat(new_attributes)
|
DiscoursePluginRegistry.define_filtered_register(register_name)
|
||||||
|
DiscoursePluginRegistry.public_send(
|
||||||
|
"register_#{register_name.singularize}",
|
||||||
|
new_attributes,
|
||||||
|
self,
|
||||||
|
)
|
||||||
|
|
||||||
reloadable_patch { klass.public_send(:define_singleton_method, method) { current_list } }
|
original_method_alias = "__original_#{method}__"
|
||||||
|
return if klass.respond_to?(original_method_alias)
|
||||||
|
reloadable_patch do
|
||||||
|
klass.singleton_class.alias_method(original_method_alias, method)
|
||||||
|
klass.define_singleton_method(method) do
|
||||||
|
public_send(original_method_alias) |
|
||||||
|
DiscoursePluginRegistry.public_send(register_name).flatten
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def directory_name
|
def directory_name
|
||||||
|
@ -599,25 +599,60 @@ TEXT
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#register_reviewable_types" do
|
describe "#register_reviewable_type" do
|
||||||
it "Overrides the existing Reviewable types adding new ones" do
|
subject(:register_reviewable_type) { plugin_instance.register_reviewable_type(new_type) }
|
||||||
current_types = Reviewable.types
|
|
||||||
new_type_class = Class
|
|
||||||
|
|
||||||
Plugin::Instance.new.register_reviewable_type new_type_class
|
context "when the provided class inherits from `Reviewable`" do
|
||||||
|
let(:new_type) { Class.new(Reviewable) }
|
||||||
|
|
||||||
expect(Reviewable.types).to match_array(current_types << new_type_class.name)
|
it "adds the provided class to the existing types" do
|
||||||
|
expect { register_reviewable_type }.to change { Reviewable.types.size }.by(1)
|
||||||
|
expect(Reviewable.types).to include(new_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when the plugin is disabled" do
|
||||||
|
before do
|
||||||
|
register_reviewable_type
|
||||||
|
plugin_instance.stubs(:enabled?).returns(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not return the new type" do
|
||||||
|
expect(Reviewable.types).not_to be_blank
|
||||||
|
expect(Reviewable.types).not_to include(new_type)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when the provided class does not inherit from `Reviewable`" do
|
||||||
|
let(:new_type) { Class }
|
||||||
|
|
||||||
|
it "does not add the provided class to the existing types" do
|
||||||
|
expect { register_reviewable_type }.not_to change { Reviewable.types }
|
||||||
|
expect(Reviewable.types).not_to be_blank
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#extend_list_method" do
|
describe "#extend_list_method" do
|
||||||
it "Overrides the existing list appending new elements" do
|
subject(:extend_list) do
|
||||||
current_list = Reviewable.types
|
plugin_instance.extend_list_method(UserHistory, :staff_actions, %i[new_action another_action])
|
||||||
new_element = Class.name
|
end
|
||||||
|
|
||||||
Plugin::Instance.new.extend_list_method Reviewable, :types, [new_element]
|
it "adds the provided values to the provided method on the provided class" do
|
||||||
|
expect { extend_list }.to change { UserHistory.staff_actions.size }.by(2)
|
||||||
|
expect(UserHistory.staff_actions).to include(:new_action, :another_action)
|
||||||
|
end
|
||||||
|
|
||||||
expect(Reviewable.types).to match_array(current_list << new_element)
|
context "when the plugin is disabled" do
|
||||||
|
before do
|
||||||
|
extend_list
|
||||||
|
plugin_instance.stubs(:enabled?).returns(false)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not return the provided values" do
|
||||||
|
expect(UserHistory.staff_actions).not_to be_blank
|
||||||
|
expect(UserHistory.staff_actions).not_to include(:new_action, :another_action)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user