mirror of
https://ghfast.top/https://github.com/discourse/discourse-follow.git
synced 2026-07-15 11:36:38 +08:00
150 lines
4.6 KiB
Ruby
150 lines
4.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class Follow::NotificationHandler
|
|
attr_reader :post
|
|
|
|
def initialize(post, notified_users)
|
|
@post = post
|
|
@notified_users = notified_users
|
|
end
|
|
|
|
def handle
|
|
return if post.post_type == Post.types[:whisper] && post.action_code.present?
|
|
return if [Post.types[:regular], Post.types[:whisper]].exclude?(post.post_type)
|
|
return if !SiteSetting.follow_notifications_enabled
|
|
return if !post.user.allow_people_to_follow_me
|
|
return if post.user.user_option&.hide_profile_and_presence
|
|
|
|
topic = post.topic
|
|
return if !topic || topic.private_message?
|
|
|
|
poster_followers.each do |follower|
|
|
next if follower.bot? || follower.staged?
|
|
next if topic_muted_by?(follower)
|
|
|
|
if post.post_number == 1
|
|
next if !follower.notify_me_when_followed_creates_topic
|
|
else
|
|
next if !follower.notify_me_when_followed_replies
|
|
end
|
|
|
|
guardian = Guardian.new(follower)
|
|
next if !guardian.can_see?(post)
|
|
|
|
if post.post_number == 1
|
|
notification_type = Notification.types[:following_created_topic]
|
|
else
|
|
notification_type = Notification.types[:following_replied]
|
|
end
|
|
|
|
# sometimes the `post_alerter_after_save_post` event can be fired twice
|
|
# for the same post resulting (incorrectly) in merged or double
|
|
# notifications. skip if we've already created a notification for this
|
|
# post
|
|
next if already_notified?(follower, notification_type)
|
|
|
|
# if the user has received a notification for the post because they're
|
|
# watching the topic, category or a tag, then delete the notification so
|
|
# they don't end up with double notifications.
|
|
#
|
|
# the `notified` array provided by the event includes users who are
|
|
# notified due to a mention (directly or via a group), quote, link to a
|
|
# post of theirs, or reply to them directly. It does not include users
|
|
# who are notified because they're watching the topic, category or a tag.
|
|
follower
|
|
.notifications
|
|
.where(
|
|
topic_id: topic.id,
|
|
notification_type: [Notification.types[:posted], Notification.types[:replied]],
|
|
post_number: post.post_number,
|
|
)
|
|
.destroy_all
|
|
|
|
# delete all existing follow notifications for the topic because we'll
|
|
# collapse them
|
|
follower
|
|
.notifications
|
|
.where(
|
|
topic_id: topic.id,
|
|
notification_type: [
|
|
Notification.types[:following_replied],
|
|
Notification.types[:following_created_topic],
|
|
],
|
|
)
|
|
.destroy_all
|
|
|
|
posts_by_following =
|
|
topic
|
|
.posts
|
|
.secured(guardian)
|
|
.where(user_id: follower.following.pluck(:id))
|
|
.where(<<~SQL, follower_id: follower.id, topic_id: topic.id)
|
|
post_number > COALESCE((
|
|
SELECT last_read_post_number FROM topic_users tu
|
|
WHERE tu.user_id = :follower_id AND tu.topic_id = :topic_id
|
|
), 0)
|
|
SQL
|
|
|
|
count = posts_by_following.count
|
|
first_unread_post = posts_by_following.order("post_number").first || post
|
|
|
|
display_username = first_unread_post.user.username
|
|
if count > 1
|
|
I18n.with_locale(follower.effective_locale) do
|
|
display_username = I18n.t("embed.replies", count: count)
|
|
end
|
|
end
|
|
|
|
notification_data = {
|
|
topic_title: topic.title,
|
|
original_post_id: post.id,
|
|
original_post_type: post.post_type,
|
|
display_username: display_username,
|
|
}
|
|
|
|
notification =
|
|
follower.notifications.create!(
|
|
notification_type: notification_type,
|
|
topic_id: topic.id,
|
|
post_number: first_unread_post.post_number,
|
|
data: notification_data.to_json,
|
|
)
|
|
@notified_users << follower
|
|
|
|
if notification&.id && !follower.suspended?
|
|
PostAlerter.create_notification_alert(
|
|
user: follower,
|
|
post: post,
|
|
notification_type: notification_type,
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def topic_muted_by?(user)
|
|
TopicUser.exists?(
|
|
topic_id: post.topic.id,
|
|
user_id: user.id,
|
|
notification_level: TopicUser.notification_levels[:muted],
|
|
)
|
|
end
|
|
|
|
def already_notified?(user, notification_type)
|
|
Notification.exists?(
|
|
topic_id: post.topic.id,
|
|
user_id: user.id,
|
|
notification_type: notification_type,
|
|
post_number: post.post_number,
|
|
)
|
|
end
|
|
|
|
def poster_followers
|
|
followers = post.user.followers
|
|
if @notified_users.present?
|
|
followers = followers.where("users.id NOT IN (?)", @notified_users.map(&:id))
|
|
end
|
|
followers
|
|
end
|
|
end
|