DEV: Add hooks to allow overriding notify_user behavior (#23850)

Adds new plugin registry `:post_action_notify_user_handlers` and more!
This commit is contained in:
Mark VanLandingham 2023-10-10 12:21:57 -05:00 committed by GitHub
parent 38e7960082
commit f29c476521
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 111 additions and 8 deletions

View File

@ -116,6 +116,8 @@ class DiscoursePluginRegistry
define_filtered_register :summarization_strategies
define_filtered_register :post_action_notify_user_handlers
def self.register_auth_provider(auth_provider)
self.auth_providers << auth_provider
end

View File

@ -58,7 +58,19 @@ module PostGuardian
if action_key == :notify_user &&
!@user.in_any_groups?(SiteSetting.personal_message_enabled_groups_map)
return false
# The modifier below is used to add additional permissions for notifying users.
# In core the only method of notifying a user is personal messages so we check if the
# user can PM. Plugins can extend the behavior of how users are notifier via `notify_user`
# post action, and this allows extension for that use case.
can_notify = false
can_notify =
DiscoursePluginRegistry.apply_modifier(
:post_guardian_can_notify_user,
can_notify,
self,
post,
)
return can_notify
end
# we allow flagging for trust level 1 and higher

View File

@ -1238,6 +1238,14 @@ class Plugin::Instance
DiscoursePluginRegistry.register_summarization_strategy(strategy, self)
end
##
# Register a block that will be called when PostActionCreator is going to notify a
# user of a post action. If any of these handlers returns false the default PostCreator
# call will be skipped.
def register_post_action_notify_user_handler(handler)
DiscoursePluginRegistry.register_post_action_notify_user_handler(handler, self)
end
protected
def self.js_path

View File

@ -116,12 +116,16 @@ class PostActionCreator
# create meta topic / post if needed
if @message.present? && %i[notify_moderators notify_user spam].include?(@post_action_name)
creator = create_message_creator
post = creator.create
if creator.errors.present?
result.add_errors_from(creator)
return result
# We need to check if the creator exists because it's possible `create_message_creator` returns nil
# in the event that a `post_action_notify_user_handler` evaluated to false, haulting the post creation.
if creator
post = creator.create
if creator.errors.present?
result.add_errors_from(creator)
return result
end
@meta_post = post
end
@meta_post = post
end
begin
@ -339,8 +343,16 @@ class PostActionCreator
else
create_args[:subtype] = TopicSubtype.notify_user
create_args[:target_usernames] = if @post_action_name == :notify_user
@post.user.username
if @post_action_name == :notify_user
create_args[:target_usernames] = @post.user.username
# Evaluate DiscoursePluginRegistry.post_action_notify_user_handlers.
# If any return false, return early from this method
handler_values =
DiscoursePluginRegistry.post_action_notify_user_handlers.map do |handler|
handler.call(@created_by, @post, @message)
end
return if handler_values.any? { |value| value == false }
elsif @post_action_name != :notify_moderators
# this is a hack to allow a PM with no recipients, we should think through
# a cleaner technique, a PM with myself is valid for flagging

View File

@ -327,4 +327,73 @@ RSpec.describe PostActionCreator do
)
end
end
describe "With plugin adding post_action_notify_user_handlers" do
let(:message) { "oh that was really bad what you said there" }
let(:plugin) { Plugin::Instance.new }
after { DiscoursePluginRegistry.reset! }
it "evaluates all handlers and creates post if none return false" do
plugin.register_post_action_notify_user_handler(
Proc.new do |user, post, message|
MessageBus.publish("notify_user", { user_id: user.id, message: message })
end,
)
plugin.register_post_action_notify_user_handler(
Proc.new do |user, post, message|
MessageBus.publish("notify_user", { poster_id: post.user_id, message: message })
end,
)
messages =
MessageBus.track_publish("notify_user") do
result =
PostActionCreator.new(
user,
post,
PostActionType.types[:notify_user],
message: message,
flag_topic: false,
).perform
post_action = result.post_action
expect(post_action.related_post).to be_present
end
expect(
messages.find { |m| m.data[:user_id] == user.id && m.data[:message] == message },
).to be_present
expect(
messages.find { |m| m.data[:poster_id] == post.user_id && m.data[:message] == message },
).to be_present
end
it "evaluates all handlers and doesn't create a post one returns false" do
plugin.register_post_action_notify_user_handler(
Proc.new do |user, post, message|
MessageBus.publish("notify_user", { user_id: user.id, message: message })
false
end,
)
messages =
MessageBus.track_publish("notify_user") do
result =
PostActionCreator.new(
user,
post,
PostActionType.types[:notify_user],
message: message,
flag_topic: false,
).perform
post_action = result.post_action
expect(post_action.related_post).not_to be_present
end
expect(
messages.find { |m| m.data[:user_id] == user.id && m.data[:message] == message },
).to be_present
end
end
end