From 30e02dbb30952eb38d0c3dd99fdcf88dfeb80b8c Mon Sep 17 00:00:00 2001 From: Chris Oliver Date: Thu, 27 Jun 2024 08:33:48 +0100 Subject: [PATCH] Add recipients feature for defining recipients inside the notifier (#459) * Add feature for defining recipients inside the notifier * Also support blocks --- CHANGELOG.md | 23 +++++++++++++ app/models/concerns/noticed/deliverable.rb | 17 ++++++++++ test/dummy/app/notifiers/comment_notifier.rb | 2 ++ test/notifier_test.rb | 34 ++++++++++++++++++++ 4 files changed, 76 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4d450c3..5f22623 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ ### Unreleased +* Add `recipients` feature to let Notifiers determine their recipients + +```ruby +class CommentNotifier < ApplicationNotifier + # Notify all the commenters on this post except the new comment author + + # Can be given a lambda or Proc + recipients ->{ params[:comment].post.commenters.excluding(params[:comment].user).distinct } + + # Can be given a block + recipients do + params[:comment].post.commenters.excluding(params[:comment].user).distinct + end + + # Or can call a method + recipients :fetch_recipients + + def fetch_recipients + params[:comment].post.commenters.excluding(params[:comment].user).distinct + end +end +``` + ### 2.3.3 * Use `public_send` for Email delivery so it doesn't accidentally call private methods. diff --git a/app/models/concerns/noticed/deliverable.rb b/app/models/concerns/noticed/deliverable.rb index 7696425..aae03c2 100644 --- a/app/models/concerns/noticed/deliverable.rb +++ b/app/models/concerns/noticed/deliverable.rb @@ -6,6 +6,7 @@ module Deliverable class_attribute :bulk_delivery_methods, instance_writer: false, default: {} class_attribute :delivery_methods, instance_writer: false, default: {} class_attribute :required_param_names, instance_writer: false, default: [] + class_attribute :_recipients, instance_writer: false end class_methods do @@ -39,6 +40,10 @@ def deliver_by(name, options = {}) delivery_methods[name] = DeliverBy.new(name, config) end + def recipients(option = nil, &block) + self._recipients = block || option + end + def required_params(*names) required_param_names.concat names end @@ -79,6 +84,8 @@ def deliver(recipients = nil, **options) # CommentNotifier.deliver(User.all, wait: 5.minutes) # CommentNotifier.deliver(User.all, wait_until: 1.hour.from_now) def deliver(recipients = nil, enqueue_job: true, **options) + recipients ||= evaluate_recipients + validate! transaction do @@ -108,6 +115,16 @@ def deliver(recipients = nil, enqueue_job: true, **options) end alias_method :deliver_later, :deliver + def evaluate_recipients + return unless _recipients + + if _recipients.respond_to?(:call) + instance_exec(&_recipients) + elsif _recipients.is_a?(Symbol) && respond_to?(_recipients) + send(_recipients) + end + end + def recipient_attributes_for(recipient) { type: "#{self.class.name}::Notification", diff --git a/test/dummy/app/notifiers/comment_notifier.rb b/test/dummy/app/notifiers/comment_notifier.rb index 63e9d99..351b9ad 100644 --- a/test/dummy/app/notifiers/comment_notifier.rb +++ b/test/dummy/app/notifiers/comment_notifier.rb @@ -1,4 +1,6 @@ class CommentNotifier < ApplicationNotifier + recipients -> { params[:recipients] } + deliver_by :test # delivery_by :email, mailer: "UserMailer", method: "new_comment" diff --git a/test/notifier_test.rb b/test/notifier_test.rb index 19ba41d..99ac26b 100644 --- a/test/notifier_test.rb +++ b/test/notifier_test.rb @@ -3,6 +3,24 @@ class NotifierTest < ActiveSupport::TestCase include ActiveJob::TestHelper + class RecipientsBlock < Noticed::Event + recipients do + params.fetch(:recipients) + end + end + + class RecipientsLambda < Noticed::Event + recipients -> { params.fetch(:recipients) } + end + + class RecipientsMethod < Noticed::Event + recipients :recipients + + def recipients + params.fetch(:recipients) + end + end + test "includes Rails urls" do assert_equal "http://localhost:3000/", SimpleNotifier.new.url end @@ -40,6 +58,22 @@ class NotifierTest < ActiveSupport::TestCase assert_equal ["can't be blank"], notifier.errors[:record] end + test "recipients block" do + assert_equal [:foo, :bar], RecipientsBlock.with(recipients: [:foo, :bar]).evaluate_recipients + end + + test "recipients lambda" do + assert_equal [:foo, :bar], RecipientsLambda.with(recipients: [:foo, :bar]).evaluate_recipients + end + + test "recipients" do + assert_equal [:foo, :bar], RecipientsMethod.with(recipients: [:foo, :bar]).evaluate_recipients + end + + test "deliver without recipients" do + ReceiptNotifier.deliver + end + test "deliver creates an event" do assert_difference "Noticed::Event.count" do ReceiptNotifier.deliver(User.first)