From d2cb17a111edfb666d5a64d1b4322fee2d788ebc Mon Sep 17 00:00:00 2001 From: Chris Oliver Date: Mon, 29 Jan 2024 13:32:20 -0600 Subject: [PATCH] Add has_noticed_notifications --- lib/noticed.rb | 1 + lib/noticed/engine.rb | 6 ++++ lib/noticed/has_notifications.rb | 49 ++++++++++++++++++++++++++++++++ test/dummy/app/models/user.rb | 4 +++ test/fixtures/noticed/events.yml | 11 +++++++ test/has_notifications_test.rb | 47 ++++++++++++++++++++++++++++++ 6 files changed, 118 insertions(+) create mode 100644 lib/noticed/has_notifications.rb create mode 100644 test/has_notifications_test.rb diff --git a/lib/noticed.rb b/lib/noticed.rb index 18d3b4b9..d006d98f 100644 --- a/lib/noticed.rb +++ b/lib/noticed.rb @@ -14,6 +14,7 @@ def self.deprecator # :nodoc: autoload :BulkDeliveryMethod, "noticed/bulk_delivery_method" autoload :Coder, "noticed/coder" autoload :DeliveryMethod, "noticed/delivery_method" + autoload :HasNotifications, "noticed/has_notifications" autoload :RequiredOptions, "noticed/required_options" autoload :Translation, "noticed/translation" diff --git a/lib/noticed/engine.rb b/lib/noticed/engine.rb index 474a2405..d44cc4f5 100644 --- a/lib/noticed/engine.rb +++ b/lib/noticed/engine.rb @@ -1,5 +1,11 @@ module Noticed class Engine < ::Rails::Engine isolate_namespace Noticed + + initializer "noticed.has_notifications" do + ActiveSupport.on_load(:active_record) do + include Noticed::HasNotifications + end + end end end diff --git a/lib/noticed/has_notifications.rb b/lib/noticed/has_notifications.rb new file mode 100644 index 00000000..10f1b0ae --- /dev/null +++ b/lib/noticed/has_notifications.rb @@ -0,0 +1,49 @@ +module Noticed + module HasNotifications + # Defines a method for the association and a before_destroy callback to remove notifications + # where this record is a param + # + # class User < ApplicationRecord + # has_noticed_notifications + # has_noticed_notifications param_name: :owner, destroy: false, model: "Notification" + # end + # + # @user.notifications_as_user + # @user.notifications_as_owner + + extend ActiveSupport::Concern + + class_methods do + def has_noticed_notifications(param_name: model_name.singular, **options) + define_method :"notifications_as_#{param_name}" do + model = options.fetch(:model_name, "Noticed::Event").constantize + case current_adapter + when "postgresql", "postgis" + model.where("params @> ?", Noticed::Coder.dump(param_name.to_sym => self).to_json) + when "mysql2" + model.where("JSON_CONTAINS(params, ?)", Noticed::Coder.dump(param_name.to_sym => self).to_json) + when "sqlite3" + model.where("json_extract(params, ?) = ?", "$.#{param_name}", Noticed::Coder.dump(self).to_json) + else + # This will perform an exact match which isn't ideal + model.where(params: {param_name.to_sym => self}) + end + end + + if options.fetch(:destroy, true) + before_destroy do + send(:"notifications_as_#{param_name}").destroy_all + end + end + end + end + + def current_adapter + if ActiveRecord::Base.respond_to?(:connection_db_config) + ActiveRecord::Base.connection_db_config.adapter + else + ActiveRecord::Base.connection_config[:adapter] + end + end + end +end diff --git a/test/dummy/app/models/user.rb b/test/dummy/app/models/user.rb index 68f955ee..b345529d 100644 --- a/test/dummy/app/models/user.rb +++ b/test/dummy/app/models/user.rb @@ -1,3 +1,7 @@ class User < ApplicationRecord has_many :notifications, as: :recipient, dependent: :destroy, class_name: "Noticed::Notification" + + # Used for querying Noticed::Event where params[:user] is a User instance + has_noticed_notifications + has_noticed_notifications param_name: :owner, destroy: false end diff --git a/test/fixtures/noticed/events.yml b/test/fixtures/noticed/events.yml index bc42c409..a85acf1c 100644 --- a/test/fixtures/noticed/events.yml +++ b/test/fixtures/noticed/events.yml @@ -23,3 +23,14 @@ three: params: foo: bar notifications_count: 2 + +account: + type: ReceiptNotifier + record: two + record_type: User + params: + foo: bar + account: + _aj_globalid: gid://dummy/Account/<%= ActiveRecord::FixtureSet.identify(:primary) %> + _aj_symbol_keys: + - account diff --git a/test/has_notifications_test.rb b/test/has_notifications_test.rb new file mode 100644 index 00000000..a80f90c1 --- /dev/null +++ b/test/has_notifications_test.rb @@ -0,0 +1,47 @@ +require "test_helper" + +class HasNotificationsTest < ActiveSupport::TestCase + test "has_noticed_notifications" do + assert User.respond_to?(:has_noticed_notifications) + end + + test "noticed notifications association" do + assert user.respond_to?(:notifications_as_user) + end + + test "noticed notifications with custom name" do + assert user.respond_to?(:notifications_as_owner) + end + + test "association returns notifications" do + assert_difference "user.notifications_as_user.count" do + SimpleNotifier.with(user: user, message: "test").deliver(user) + end + end + + test "association with custom name returns notifications" do + assert_difference "user.notifications_as_owner.count" do + SimpleNotifier.with(owner: user, message: "test").deliver(user) + end + end + + test "deletes notifications with matching param" do + SimpleNotifier.with(user: user, message: "test").deliver(users(:two)) + + assert_difference "Noticed::Event.count", -1 do + user.destroy + end + end + + test "doesn't delete notifications when disabled" do + SimpleNotifier.with(owner: user, message: "test").deliver(users(:two)) + + assert_no_difference "Noticed::Event.count" do + user.destroy + end + end + + def user + @user ||= users(:one) + end +end