Validate we don't create overlapping bundles
This commit is contained in:
@@ -3,10 +3,20 @@ class Notification::Bundle < ApplicationRecord
|
||||
|
||||
enum :status, %i[ pending processing delivered ]
|
||||
|
||||
before_create :set_default_window
|
||||
|
||||
scope :due, -> { pending.where("ends_at <= ?", Time.current) }
|
||||
scope :containing, -> (notification) { where("starts_at <= ? AND ends_at >= ?", notification.created_at, notification.created_at) }
|
||||
scope :overlapping_with, -> (other_bundle) {
|
||||
where(
|
||||
"(starts_at <= ? AND ends_at >= ?) OR (starts_at <= ? AND ends_at >= ?) OR (starts_at >= ? AND ends_at <= ?)",
|
||||
other_bundle.starts_at, other_bundle.starts_at,
|
||||
other_bundle.ends_at, other_bundle.ends_at,
|
||||
other_bundle.starts_at, other_bundle.ends_at
|
||||
)
|
||||
}
|
||||
|
||||
before_create :set_default_window
|
||||
|
||||
validate :validate_no_overlapping
|
||||
|
||||
class << self
|
||||
def deliver_all
|
||||
@@ -51,4 +61,14 @@ class Notification::Bundle < ApplicationRecord
|
||||
def has_unread_notifications?
|
||||
notifications.unread.any?
|
||||
end
|
||||
|
||||
def validate_no_overlapping
|
||||
if overlapping_bundles.exists?
|
||||
errors.add(:base, "Bundle window overlaps with an existing pending bundle")
|
||||
end
|
||||
end
|
||||
|
||||
def overlapping_bundles
|
||||
user.notification_bundles.where.not(id: id).overlapping_with(self)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,6 +30,47 @@ class Notification::BundleTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
bundle_1, bundle_2 = @user.notification_bundles.last(2)
|
||||
assert_includes bundle_1.notifications, notification_1
|
||||
assert_includes bundle_1.notifications, notification_2
|
||||
assert_includes bundle_2.notifications, notification_3
|
||||
end
|
||||
|
||||
test "overlapping bundles are invalid" do
|
||||
bundle_1 = @user.notification_bundles.create!(
|
||||
starts_at: Time.current,
|
||||
ends_at: 4.hours.from_now,
|
||||
status: :pending
|
||||
)
|
||||
|
||||
bundle_2 = @user.notification_bundles.build(
|
||||
starts_at: 2.hours.from_now,
|
||||
ends_at: 6.hours.from_now,
|
||||
status: :pending
|
||||
)
|
||||
assert_not bundle_2.valid?
|
||||
|
||||
# Bundle with overlapping end time should be invalid
|
||||
bundle_3 = @user.notification_bundles.build(
|
||||
starts_at: 2.hours.ago,
|
||||
ends_at: 2.hours.from_now,
|
||||
status: :pending
|
||||
)
|
||||
assert_not bundle_3.valid?
|
||||
|
||||
# Bundle completely within another bundle should be invalid
|
||||
bundle_4 = @user.notification_bundles.build(
|
||||
starts_at: 1.hour.from_now,
|
||||
ends_at: 3.hours.from_now,
|
||||
status: :pending
|
||||
)
|
||||
assert_not bundle_4.valid?
|
||||
|
||||
# Non-overlapping bundle should be valid
|
||||
bundle_5 = @user.notification_bundles.build(
|
||||
starts_at: 5.hours.from_now,
|
||||
ends_at: 9.hours.from_now,
|
||||
status: :pending
|
||||
)
|
||||
assert bundle_5.valid?
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user