Skip to content

Commit 161c728

Browse files
committed
feat: Refactor event reminder job and notifier to use params for event and recipient, add tests for job functionality
1 parent a233dac commit 161c728

File tree

7 files changed

+228
-219
lines changed

7 files changed

+228
-219
lines changed

app/jobs/better_together/event_reminder_job.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def send_reminders_to_attendees(event, attendees, reminder_type)
4545

4646
def send_reminder_to_attendee(event, attendee, reminder_type)
4747
BetterTogether::EventReminderNotifier.with(
48-
event: event,
48+
record: event,
4949
reminder_type: reminder_type
5050
).deliver(attendee)
5151
rescue StandardError => e

app/mailers/better_together/event_mailer.rb

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,28 @@ module BetterTogether
44
# Mailer for event-related notifications
55
class EventMailer < ApplicationMailer
66
# Sends event reminder emails
7-
def event_reminder(recipient, event, reminder_type = '24_hours')
8-
@event = event
9-
@reminder_type = reminder_type
10-
@recipient = recipient
7+
def event_reminder
8+
@event = params[:event]
9+
@reminder_type = params[:reminder_type] || '24_hours'
10+
@recipient = params[:person]
1111
@platform = BetterTogether::Platform.find_by(host: true)
1212

1313
mail(
14-
to: recipient.email,
15-
subject: reminder_subject(event)
14+
to: @recipient.email,
15+
subject: reminder_subject(@event)
1616
)
1717
end
1818

1919
# Sends event update emails
20-
def event_update(recipient, event, changed_attributes)
21-
@event = event
22-
@changed_attributes = changed_attributes
23-
@recipient = recipient
20+
def event_update
21+
@event = params[:event]
22+
@changed_attributes = params[:changed_attributes]
23+
@recipient = params[:person]
2424
@platform = BetterTogether::Platform.find_by(host: true)
2525

2626
mail(
27-
to: recipient.email,
28-
subject: update_subject(event)
27+
to: @recipient.email,
28+
subject: update_subject(@event)
2929
)
3030
end
3131

app/notifiers/better_together/event_reminder_notifier.rb

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,28 @@ class EventReminderNotifier < ApplicationNotifier
77
config.if = -> { should_notify? }
88
end
99
deliver_by :email, mailer: 'BetterTogether::EventMailer', method: :event_reminder, params: :email_params do |config|
10-
config.if = -> { recipient_has_email? && should_notify? }
10+
config.wait = 15.minutes
11+
config.if = -> { send_email_notification? }
1112
end
1213

13-
param :event, :reminder_type
14+
validates :record, presence: true
15+
required_param :reminder_type
1416

15-
notification_methods do
16-
delegate :event, :reminder_type, to: :event
17+
def event
18+
record
19+
end
20+
21+
def reminder_type
22+
params[:reminder_type] || '24_hours'
1723
end
1824

19-
def event = params[:event]
20-
def reminder_type = params[:reminder_type] || '24_hours'
25+
def identifier
26+
event.id
27+
end
28+
29+
def url
30+
::BetterTogether::Engine.routes.url_helpers.event_url(event, locale: I18n.locale)
31+
end
2132

2233
def title
2334
I18n.t('better_together.notifications.event_reminder.title',
@@ -36,12 +47,22 @@ def body
3647
end
3748
end
3849

39-
def build_message(_notification)
40-
{ title:, body: }
50+
def build_message(notification)
51+
{
52+
title:,
53+
body:,
54+
identifier:,
55+
url:,
56+
unread_count: notification.recipient.notifications.unread.count
57+
}
4158
end
4259

4360
def email_params(_notification)
44-
{ event:, reminder_type: }
61+
{
62+
event: event,
63+
person: recipient,
64+
reminder_type: reminder_type
65+
}
4566
end
4667

4768
private
@@ -72,17 +93,35 @@ def formatted_start_time
7293
end
7394

7495
notification_methods do
75-
def recipient_has_email?
76-
recipient.respond_to?(:email) && recipient.email.present? &&
77-
(!recipient.respond_to?(:notification_preferences) ||
78-
recipient.notification_preferences.fetch('notify_by_email', true))
96+
delegate :event, to: :event
97+
delegate :url, to: :event
98+
delegate :identifier, to: :event
99+
delegate :reminder_type, to: :event
100+
101+
def send_email_notification?
102+
recipient.email.present? && recipient.notify_by_email && should_send_email?
79103
end
80104

81105
def should_notify?
82106
event.present? && event.starts_at.present? &&
83107
(!recipient.respond_to?(:notification_preferences) ||
84108
recipient.notification_preferences.fetch('event_reminders', true))
85109
end
110+
111+
def should_send_email?
112+
# Check for unread notifications for the recipient for the record's event
113+
unread_notifications = recipient.notifications.where(
114+
event_id: BetterTogether::EventReminderNotifier.where(params: { event_id: event.id }).select(:id),
115+
read_at: nil
116+
).order(created_at: :desc)
117+
118+
if unread_notifications.none?
119+
false
120+
else
121+
# Only send one email per unread notifications per event
122+
event.id == unread_notifications.last.event.record_id
123+
end
124+
end
86125
end
87126
end
88127
end
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# frozen_string_literal: true
2+
3+
require 'rails_helper'
4+
5+
module BetterTogether
6+
RSpec.describe EventReminderJob do
7+
include ActiveJob::TestHelper
8+
9+
let(:person) { create(:person) }
10+
let(:event) { create(:event, :upcoming, :with_attendees) }
11+
12+
describe '#perform' do
13+
context 'with valid event' do
14+
it 'sends reminders to all going attendees' do
15+
expect do
16+
described_class.perform_now(event)
17+
end.to change(Noticed::Notification, :count).by_at_least(1)
18+
end
19+
20+
it 'accepts reminder type parameter' do
21+
expect do
22+
described_class.perform_now(event, '1_hour')
23+
end.not_to raise_error
24+
end
25+
end
26+
27+
context 'with invalid event' do
28+
it 'handles missing event gracefully' do
29+
expect do
30+
described_class.perform_now(nil)
31+
end.not_to raise_error
32+
end
33+
34+
it 'handles event without start time' do
35+
draft_event = create(:event, :draft)
36+
expect do
37+
described_class.perform_now(draft_event)
38+
end.not_to raise_error
39+
end
40+
end
41+
42+
context 'when event has no attendees' do
43+
let(:event_without_attendees) { create(:event, :upcoming) }
44+
45+
it 'completes without sending notifications' do
46+
expect do
47+
described_class.perform_now(event_without_attendees)
48+
end.not_to change(Noticed::Notification, :count)
49+
end
50+
end
51+
end
52+
53+
describe 'queue configuration' do
54+
it 'uses the notifications queue' do
55+
expect(described_class.queue_name).to eq('notifications')
56+
end
57+
end
58+
59+
describe 'retry and error handling' do
60+
it 'handles errors gracefully' do
61+
allow_any_instance_of(described_class).to receive(:find_event).and_raise(StandardError, 'Test error')
62+
expect do
63+
described_class.perform_now(event)
64+
end.not_to raise_error
65+
end
66+
67+
it 'handles missing events gracefully' do
68+
expect do
69+
described_class.perform_now(999_999)
70+
end.not_to raise_error
71+
end
72+
end
73+
end
74+
end

0 commit comments

Comments
 (0)