Files
Rosa Gutierrez 05819f84a2 Refactor notification push system with registry pattern
Replace NotificationPusher with a cleaner architecture:

- Add Notification::Pushable concern with push target registry
- Add Notification::Push base class with template methods
- Add Notification::Push::Web for web push (OSS)
- Add Notification::Push::Native for native push (SaaS)
- Add Notification::WebPushJob and Notification::NativePushJob

Key design:
- Registry pattern: Notification.register_push_target(:web)
- Template method: push calls should_push? then perform_push
- Subclasses override should_push? (with super) and perform_push
- Each target handles its own job enqueueing

Also:
- Add Notification#pushable? for checking push eligibility
- Add Notification#identity delegation to user
- Reorganize tests to match new class structure

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Tidy up saas engine a bit more
2026-02-25 19:31:13 +01:00

71 lines
1.6 KiB
Ruby

class Notification < ApplicationRecord
include Notification::Pushable
belongs_to :account, default: -> { user.account }
belongs_to :user
belongs_to :creator, class_name: "User"
belongs_to :source, polymorphic: true
belongs_to :card
scope :unread, -> { where(read_at: nil) }
scope :read, -> { where.not(read_at: nil) }
scope :ordered, -> { order(read_at: :desc, updated_at: :desc) }
scope :preloaded, -> {
preload(
:creator, :account,
card: [ :board, :column, :closure, :not_now ],
source: [ :board, :creator, { eventable: [ :closure, :board, :assignments ] } ]
)
}
before_validation :set_card
after_create :bundle
after_update :bundle, if: :source_id_previously_changed?
after_create_commit -> { broadcast_prepend_later_to user, :notifications, target: "notifications" }
after_update_commit -> { broadcast_update }
after_destroy_commit -> { broadcast_remove_to user, :notifications }
delegate :notifiable_target, to: :source
delegate :identity, to: :user
class << self
def read_all
all.each(&:read)
end
def unread_all
all.each(&:unread)
end
end
def read
update!(read_at: Time.current, unread_count: 0)
end
def unread
update!(read_at: nil, unread_count: 1)
end
def read?
read_at.present?
end
private
def set_card
self.card = source.card
end
def bundle
user.bundle(self) if user.settings.bundling_emails?
end
def broadcast_update
if read?
broadcast_remove_to(user, :notifications)
else
broadcast_prepend_later_to(user, :notifications, target: "notifications")
end
end
end