discourse/app/services/topic_bookmarkable.rb
Martin Brennan a176b57be0
FIX: Use bookmarkable pattern for bookmark cleanup (#17202)
We have a `cleanup!` class method on bookmarks that deletes
bookmarks X days after their related record (post/topic) are
deleted. This commit changes this method to use the
registered_bookmarkables for this instead, and each bookmarkable
type can delete related bookmarks in their own way.
2022-06-23 14:09:39 +10:00

91 lines
2.8 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
[:topic_users, :tags, { posts: :user }]
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)
bookmark.user.notifications.create!(
notification_type: Notification.types[:bookmark_reminder],
topic_id: bookmark.bookmarkable_id,
post_number: 1,
data: {
title: bookmark.bookmarkable.title,
display_username: bookmark.user.username,
bookmark_name: bookmark.name,
bookmarkable_url: bookmark.bookmarkable.first_post.url
}.to_json
)
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