DEV: Plugin instance method for push_notification_filters (#14787)

DEV: Plugin instance method for push_notification_filters (#14787)

diff --git a/.ruby-version b/.ruby-version
new file mode 100644
index 0000000..cb2b00e
--- /dev/null
+++ b/.ruby-version
@@ -0,0 +1 @@
+3.0.1
diff --git a/app/services/post_alerter.rb b/app/services/post_alerter.rb
index 081fd70..7b49d0d 100644
--- a/app/services/post_alerter.rb
+++ b/app/services/post_alerter.rb
@@ -37,6 +37,10 @@ class PostAlerter
   def self.push_notification(user, payload)
     return if user.do_not_disturb?
 
+    DiscoursePluginRegistry.push_notification_filters.each do |filter|
+      return unless filter.call(user, payload)
+    end
+
     if user.push_subscriptions.exists?
       Jobs.enqueue(:send_push_notification, user_id: user.id, payload: payload)
     end
diff --git a/lib/discourse_plugin_registry.rb b/lib/discourse_plugin_registry.rb
index 8106809..53a05aa 100644
--- a/lib/discourse_plugin_registry.rb
+++ b/lib/discourse_plugin_registry.rb
@@ -91,6 +91,8 @@ class DiscoursePluginRegistry
 
   define_filtered_register :presence_channel_prefixes
 
+  define_filtered_register :push_notification_filters
+
   def self.register_auth_provider(auth_provider)
     self.auth_providers << auth_provider
   end
diff --git a/lib/plugin/instance.rb b/lib/plugin/instance.rb
index 7158f0d..fe8a029 100644
--- a/lib/plugin/instance.rb
+++ b/lib/plugin/instance.rb
@@ -950,6 +950,12 @@ class Plugin::Instance
     DiscoursePluginRegistry.register_presence_channel_prefix([prefix, block], self)
   end
 
+  # Registers a new push notification filter. User and notification payload are passed into block, and if all
+  # filters return `true`, the push notification will be sent.
+  def register_push_notification_filter(&block)
+    DiscoursePluginRegistry.register_push_notification_filter(block, self)
+  end
+
   # Register a ReviewableScore setting_name associated with a reason.
   # We'll use this to build a site setting link and add it to the reason's translation.
   #
diff --git a/spec/services/post_alerter_spec.rb b/spec/services/post_alerter_spec.rb
index c9da511..5633886 100644
--- a/spec/services/post_alerter_spec.rb
+++ b/spec/services/post_alerter_spec.rb
@@ -721,12 +721,8 @@ describe PostAlerter do
   describe "push_notification" do
     let(:mention_post) { create_post_with_alerts(user: user, raw: 'Hello @eviltrout :heart:') }
     let(:topic) { mention_post.topic }
-
-    it "pushes nothing to suspended users" do
+    before do
       SiteSetting.allowed_user_api_push_urls = "https://site.com/push|https://site2.com/push"
-
-      evil_trout.update_columns(suspended_till: 1.year.from_now)
-
       2.times do |i|
         UserApiKey.create!(user_id: evil_trout.id,
                            client_id: "xxx#{i}",
@@ -734,20 +730,33 @@ describe PostAlerter do
                            scopes: ['notifications'].map { |name| UserApiKeyScope.new(name: name) },
                            push_url: "https://site2.com/push")
       end
+    end
+
+    describe "DiscoursePluginRegistry#push_notification_filters" do
+      it "sends push notifications when all filters pass" do
+        Plugin::Instance.new.register_push_notification_filter do |user, payload|
+          true
+        end
+
+        expect { mention_post }.to change { Jobs::PushNotification.jobs.count }.by(1)
+        DiscoursePluginRegistry.reset!
+      end
 
+      it "does not send push notifications when a filters returns false" do
+        Plugin::Instance.new.register_push_notification_filter do |user, payload|
+          false
+        end
+        expect { mention_post }.not_to change { Jobs::PushNotification.jobs.count }
+        DiscoursePluginRegistry.reset!
+      end
+    end
+
+    it "pushes nothing to suspended users" do
+      evil_trout.update_columns(suspended_till: 1.year.from_now)
       expect { mention_post }.to_not change { Jobs::PushNotification.jobs.count }
     end
 
     it "pushes nothing when the user is in 'do not disturb'" do
-      SiteSetting.allowed_user_api_push_urls = "https://site.com/push|https://site2.com/push"
-      2.times do |i|
-        UserApiKey.create!(user_id: evil_trout.id,
-                           client_id: "xxx#{i}",
-                           application_name: "iPhone#{i}",
-                           scopes: ['notifications'].map { |name| UserApiKeyScope.new(name: name) },
-                           push_url: "https://site2.com/push")
-      end
-
       Fabricate(:do_not_disturb_timing, user: evil_trout, starts_at: Time.zone.now, ends_at: 1.day.from_now)
 
       expect { mention_post }.to_not change { Jobs::PushNotification.jobs.count }
@@ -755,16 +764,6 @@ describe PostAlerter do
 
     it "correctly pushes notifications if configured correctly" do
       Jobs.run_immediately!
-      SiteSetting.allowed_user_api_push_urls = "https://site.com/push|https://site2.com/push"
-
-      2.times do |i|
-        UserApiKey.create!(user_id: evil_trout.id,
-                           client_id: "xxx#{i}",
-                           application_name: "iPhone#{i}",
-                           scopes: ['notifications'].map { |name| UserApiKeyScope.new(name: name) },
-                           push_url: "https://site2.com/push")
-      end
-
       body = nil
       headers = nil
 

GitHub sha: 67265a50453aeafb8ca634cff714ea47cfd24efb

This commit appears in #14787 which was approved by eviltrout. It was merged by markvanlan.