FIX: phantom notification when being added to an event in a message... (#35459)

... you don't have access to.

Before creating the notification for an event, we weren't checking
whether the invitee had access to the topic, thus generating phantom
notification (aka. a number in the hamburger menu, but no notification
item in any lists).

Also made sure that creating a private event without any invitees, does
not generate invites for ... everyone 😅
This commit is contained in:
Régis Hanol
2025-10-17 09:04:21 +02:00
committed by GitHub
parent e2eb9fe93f
commit b99e47cfae
2 changed files with 45 additions and 1 deletions
@@ -224,6 +224,7 @@ module DiscoursePostEvent
def create_notification!(user, post, predefined_attendance: false)
return if post.event.starts_at.nil? || post.event.starts_at < Time.current
return if !Guardian.new(user).can_see?(post)
message =
if predefined_attendance
@@ -383,6 +384,8 @@ module DiscoursePostEvent
.where.not(id: excluded_ids)
.select(:id)
User.where(id: user_ids)
elsif self.private?
User.none
else
users.where.not(id: excluded_ids)
end
@@ -104,6 +104,31 @@ describe DiscoursePostEvent::Event do
}
end
end
describe "with private message topics" do
let(:pm_owner) { Fabricate(:user) }
let(:allowed_user) { Fabricate(:user) }
let(:disallowed_user) { Fabricate(:user) }
let(:pm_topic) do
Fabricate(:private_message_topic, user: pm_owner, recipient: allowed_user)
end
let(:pm_post) { Fabricate(:post, topic: pm_topic, user: pm_owner) }
let(:pm_event) { Fabricate(:event, post: pm_post) }
it "does not send notifications to users without access to the PM" do
expect(Guardian.new(disallowed_user).can_see?(pm_topic)).to be(false)
expect { pm_event.create_notification!(disallowed_user, pm_post) }.not_to change {
Notification.count
}
end
it "does send notifications to users with access to the PM" do
expect(Guardian.new(allowed_user).can_see?(pm_topic)).to be(true)
expect { pm_event.create_notification!(allowed_user, pm_post) }.to change {
Notification.count
}.by(1)
end
end
end
end
@@ -609,13 +634,29 @@ describe DiscoursePostEvent::Event do
before { DiscoursePostEvent::Invitee.create_attendance!(user_3.id, post_1.id, :going) }
it "doesnt return already attending user" do
it "doesn't return already attending user" do
expect(event_1.missing_users.pluck(:id)).to_not include(user_3.id)
end
it "return users from groups with no duplicates" do
expect(event_1.missing_users.pluck(:id)).to match_array([user_1.id, user_2.id])
end
context "with private event with empty raw_invitees" do
let!(:event_without_invitees) do
Fabricate(
:event,
post: Fabricate(:post),
status: DiscoursePostEvent::Event.statuses[:private],
raw_invitees: [],
)
end
it "does not return all site users" do
expect(event_without_invitees.missing_users.count).to eq(0)
expect(User.real.activated.not_silenced.not_suspended.not_staged.count).not_to eq(0)
end
end
end
describe "#calculate_next_date" do