discourse/app/services/topic_bookmarkable.rb
Martin Brennan 49a70a37f1
FIX: Remove last_unread_post excerpt logic for bookmarks (#17979)
The logic to determine what post excerpt to show for
a topic-level bookmark based on the last unread post
was complex and slow, so we decided to remove it and
always just use the first post excerpt.

This commit also fixes an issue where a couple of
instances of for_topic were missed when doing the
Bookmarkable refactors, so:

1. Clicking the topic bookmark link was not taking
   the user to the last unread post
2. When replying to a topic where there was a topic
   level bookmark with the auto delete preference
   of "on owner reply", we were not removing the
   bookmark from the UI correctly.

A test has been added for the former, the latter would
be quite time-consuming to test and not really worth
it considering it's quite an edge case UI bug.
2022-08-19 09:35:25 +10:00

98 lines
2.9 KiB
Ruby

# frozen_string_literal: true
class TopicBookmarkable < BaseBookmarkable
include TopicPostBookmarkableHelper
def self.model
Topic
end
def self.serializer
UserTopicBookmarkSerializer
end
def self.preload_associations
[:tags, { first_post: :user }]
end
def self.perform_custom_preload!(topic_bookmarks, guardian)
topics = topic_bookmarks.map(&:bookmarkable)
topic_user_lookup = TopicUser.lookup_for(guardian.user, topics)
topics.each do |topic|
topic.user_data = topic_user_lookup[topic.id]
end
end
def self.list_query(user, guardian)
topics = Topic.listable_topics.secured(guardian)
pms = Topic.private_messages_for_user(user)
topic_bookmarks = user
.bookmarks_of_type("Topic")
.joins("INNER JOIN topics ON topics.id = bookmarks.bookmarkable_id AND bookmarks.bookmarkable_type = 'Topic'")
.joins("LEFT JOIN topic_users ON topic_users.topic_id = topics.id")
.where("topic_users.user_id = ?", user.id)
guardian.filter_allowed_categories(topic_bookmarks.merge(topics.or(pms)))
end
def self.search_query(bookmarks, query, ts_query, &bookmarkable_search)
bookmarkable_search.call(
bookmarks
.joins("LEFT JOIN posts ON posts.topic_id = topics.id AND posts.post_number = 1")
.joins("LEFT JOIN post_search_data ON post_search_data.post_id = posts.id"),
"#{ts_query} @@ post_search_data.search_data"
)
end
def self.reminder_handler(bookmark)
send_reminder_notification(
bookmark,
topic_id: bookmark.bookmarkable_id,
post_number: 1,
data: {
title: bookmark.bookmarkable.title,
bookmarkable_url: bookmark.bookmarkable.first_post.url
}
)
end
def self.reminder_conditions(bookmark)
bookmark.bookmarkable.present?
end
def self.can_see?(guardian, bookmark)
guardian.can_see_topic?(bookmark.bookmarkable)
end
def self.bookmark_metadata(bookmark, user)
{ topic_bookmarked: Bookmark.for_user_in_topic(user.id, bookmark.bookmarkable.id).exists? }
end
def self.validate_before_create(guardian, bookmarkable)
raise Discourse::InvalidAccess if bookmarkable.blank? || !guardian.can_see_topic?(bookmarkable)
end
def self.after_create(guardian, bookmark, opts)
sync_topic_user_bookmarked(guardian.user, bookmark.bookmarkable, opts)
end
def self.after_destroy(guardian, bookmark, opts)
sync_topic_user_bookmarked(guardian.user, bookmark.bookmarkable, opts)
end
def self.cleanup_deleted
related_topics = DB.query(<<~SQL, grace_time: 3.days.ago)
DELETE FROM bookmarks b
USING topics t
WHERE b.bookmarkable_id = t.id AND b.bookmarkable_type = 'Topic'
AND (t.deleted_at < :grace_time)
RETURNING t.id AS topic_id
SQL
related_topics_ids = related_topics.map(&:topic_id).uniq
related_topics_ids.each do |topic_id|
Jobs.enqueue(:sync_topic_user_bookmarked, topic_id: topic_id)
end
end
end