DEV: Add `post_alerter_after_save_post` event (#14388)

DEV: Add post_alerter_after_save_post event (#14388)

Also promote the create_notification_alert and push_notification methods from instance methods to class methods so that plugins can call them. This is temporary until we add a more comprehensive API for extending PostAlerter.

diff --git a/app/services/post_alerter.rb b/app/services/post_alerter.rb
index 90b4516..27eafed 100644
--- a/app/services/post_alerter.rb
+++ b/app/services/post_alerter.rb
@@ -13,6 +13,48 @@ class PostAlerter
     post
   end
 
+  def self.create_notification_alert(user:, post:, notification_type:, excerpt: nil, username: nil)
+    if post_url = post.url
+      payload = {
+       notification_type: notification_type,
+       post_number: post.post_number,
+       topic_title: post.topic.title,
+       topic_id: post.topic.id,
+       excerpt: excerpt || post.excerpt(400, text_entities: true, strip_links: true, remap_emoji: true),
+       username: username || post.username,
+       post_url: post_url
+      }
+
+      DiscourseEvent.trigger(:pre_notification_alert, user, payload)
+      MessageBus.publish("/notification-alert/#{user.id}", payload, user_ids: [user.id])
+      push_notification(user, payload)
+      DiscourseEvent.trigger(:post_notification_alert, user, payload)
+    end
+  end
+
+  def self.push_notification(user, payload)
+    return if user.do_not_disturb?
+
+    if user.push_subscriptions.exists?
+      Jobs.enqueue(:send_push_notification, user_id: user.id, payload: payload)
+    end
+
+    if SiteSetting.allow_user_api_key_scopes.split("|").include?("push") && SiteSetting.allowed_user_api_push_urls.present?
+      clients = user.user_api_keys
+        .joins(:scopes)
+        .where("user_api_key_scopes.name IN ('push', 'notifications')")
+        .where("push_url IS NOT NULL AND push_url <> ''")
+        .where("position(push_url IN ?) > 0", SiteSetting.allowed_user_api_push_urls)
+        .where("revoked_at IS NULL")
+        .order(client_id: :asc)
+        .pluck(:client_id, :push_url)
+
+      if clients.length > 0
+        Jobs.enqueue(:push_notification, clients: clients, payload: payload, user_id: user.id)
+      end
+    end
+  end
+
   def initialize(default_opts = {})
     @default_opts = default_opts
   end
@@ -115,6 +157,8 @@ class PostAlerter
         notify_first_post_watchers(post, watchers)
       end
     end
+
+    DiscourseEvent.trigger(:post_alerter_after_save_post, post, new_record, notified)
   end
 
   def group_watchers(topic)
@@ -144,7 +188,7 @@ class PostAlerter
 
     # Don't notify the OP
     user_ids -= [post.user_id]
-    users = User.where(id: user_ids)
+    users = User.where(id: user_ids).includes(:do_not_disturb_timings)
 
     DiscourseEvent.trigger(:before_create_notifications_for_users, users, post)
     each_user_in_batches(users) do |user|
@@ -466,45 +510,17 @@ class PostAlerter
   end
 
   def create_notification_alert(user:, post:, notification_type:, excerpt: nil, username: nil)
-    if post_url = post.url
-      payload = {
-       notification_type: notification_type,
-       post_number: post.post_number,
-       topic_title: post.topic.title,
-       topic_id: post.topic.id,
-       excerpt: excerpt || post.excerpt(400, text_entities: true, strip_links: true, remap_emoji: true),
-       username: username || post.username,
-       post_url: post_url
-      }
-
-      DiscourseEvent.trigger(:pre_notification_alert, user, payload)
-      MessageBus.publish("/notification-alert/#{user.id}", payload, user_ids: [user.id])
-      push_notification(user, payload)
-      DiscourseEvent.trigger(:post_notification_alert, user, payload)
-    end
+    self.class.create_notification_alert(
+      user: user,
+      post: post,
+      notification_type: notification_type,
+      excerpt: excerpt,
+      username: username
+    )
   end
 
   def push_notification(user, payload)
-    return if user.do_not_disturb?
-
-    if user.push_subscriptions.exists?
-      Jobs.enqueue(:send_push_notification, user_id: user.id, payload: payload)
-    end
-
-    if SiteSetting.allow_user_api_key_scopes.split("|").include?("push") && SiteSetting.allowed_user_api_push_urls.present?
-      clients = user.user_api_keys
-        .joins(:scopes)
-        .where("user_api_key_scopes.name IN ('push', 'notifications')")
-        .where("push_url IS NOT NULL AND push_url <> ''")
-        .where("position(push_url IN ?) > 0", SiteSetting.allowed_user_api_push_urls)
-        .where("revoked_at IS NULL")
-        .order(client_id: :asc)
-        .pluck(:client_id, :push_url)
-
-      if clients.length > 0
-        Jobs.enqueue(:push_notification, clients: clients, payload: payload, user_id: user.id)
-      end
-    end
+    self.class.push_notification(user, payload)
   end
 
   def expand_group_mentions(groups, post)
@@ -527,7 +543,7 @@ class PostAlerter
     groups = nil if groups.empty?
 
     if mentions.present?
-      users = User.where(username_lower: mentions).where.not(id: post.user_id)
+      users = User.where(username_lower: mentions).includes(:do_not_disturb_timings).where.not(id: post.user_id)
       users = nil if users.empty?
     end
 
@@ -776,7 +792,7 @@ class PostAlerter
   def each_user_in_batches(users)
     # This is race-condition-safe, unlike #find_in_batches
     users.pluck(:id).each_slice(USER_BATCH_SIZE) do |user_ids_batch|
-      User.where(id: user_ids_batch).each { |user| yield(user) }
+      User.where(id: user_ids_batch).includes(:do_not_disturb_timings).each { |user| yield(user) }
     end
   end
 end

GitHub sha: 37a3bf9c118480b8fbae58bbcb798d8b9c6792cf

This commit appears in #14388 which was approved by eviltrout. It was merged by OsamaSayegh.