mirror of
https://github.com/discourse/discourse.git
synced 2024-11-22 10:57:04 +08:00
DEV: Add backend support for unread and new topics list (#20293)
This commit adds backend support for a new topics list that combines both the current unread and new topics lists. We're going to experiment with this new list (name TBD) internally and decide if this feature is something that we want to fully build. Internal topic: t/77234.
This commit is contained in:
parent
c541bd05a8
commit
5423e7c5b7
|
@ -507,21 +507,7 @@ class TopicQuery
|
|||
whisperer: @user&.whisperer?,
|
||||
).order("CASE WHEN topics.user_id = tu.user_id THEN 1 ELSE 2 END")
|
||||
|
||||
if @user
|
||||
# micro optimisation so we don't load up all of user stats which we do not need
|
||||
unread_at =
|
||||
DB.query_single("select first_unread_at from user_stats where user_id = ?", @user.id).first
|
||||
|
||||
if max_age = options[:max_age]
|
||||
max_age_date = max_age.days.ago
|
||||
unread_at ||= max_age_date
|
||||
unread_at = unread_at > max_age_date ? unread_at : max_age_date
|
||||
end
|
||||
|
||||
# perf note, in the past we tried doing this in a subquery but performance was
|
||||
# terrible, also tried with a join and it was bad
|
||||
result = result.where("topics.updated_at >= ?", unread_at)
|
||||
end
|
||||
result = apply_max_age_limit(result, options)
|
||||
|
||||
self.class.results_filter_callbacks.each do |filter_callback|
|
||||
result = filter_callback.call(:unread, result, @user, options)
|
||||
|
@ -548,6 +534,28 @@ class TopicQuery
|
|||
suggested_ordering(result, options)
|
||||
end
|
||||
|
||||
def new_and_unread_results(options = {})
|
||||
base = default_results(options.reverse_merge(unordered: true))
|
||||
|
||||
new_results =
|
||||
TopicQuery.new_filter(
|
||||
base,
|
||||
treat_as_new_topic_start_date: @user.user_option.treat_as_new_topic_start_date,
|
||||
)
|
||||
new_results = remove_muted(new_results, @user, options)
|
||||
new_results = remove_dismissed(new_results, @user)
|
||||
|
||||
unread_results =
|
||||
apply_max_age_limit(TopicQuery.unread_filter(base, whisperer: @user&.whisperer?), options)
|
||||
|
||||
base.joins_values.concat(new_results.joins_values, unread_results.joins_values)
|
||||
base.joins_values.uniq!
|
||||
results = base.merge(new_results.or(unread_results))
|
||||
|
||||
results = results.order("CASE WHEN topics.user_id = tu.user_id THEN 1 ELSE 2 END")
|
||||
suggested_ordering(results, options)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def per_page_setting
|
||||
|
@ -1167,4 +1175,23 @@ class TopicQuery
|
|||
col_name = whisperer ? "highest_staff_post_number" : "highest_post_number"
|
||||
list.where("tu.last_read_post_number IS NULL OR tu.last_read_post_number < topics.#{col_name}")
|
||||
end
|
||||
|
||||
def apply_max_age_limit(results, options)
|
||||
if @user
|
||||
# micro optimisation so we don't load up all of user stats which we do not need
|
||||
unread_at =
|
||||
DB.query_single("select first_unread_at from user_stats where user_id = ?", @user.id).first
|
||||
|
||||
if max_age = options[:max_age]
|
||||
max_age_date = max_age.days.ago
|
||||
unread_at ||= max_age_date
|
||||
unread_at = unread_at > max_age_date ? unread_at : max_age_date
|
||||
end
|
||||
|
||||
# perf note, in the past we tried doing this in a subquery but performance was
|
||||
# terrible, also tried with a join and it was bad
|
||||
results = results.where("topics.updated_at >= ?", unread_at)
|
||||
end
|
||||
results
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1731,4 +1731,146 @@ RSpec.describe TopicQuery do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#new_and_unread_results" do
|
||||
fab!(:unread_topic) { Fabricate(:post).topic }
|
||||
fab!(:new_topic) { Fabricate(:post).topic }
|
||||
fab!(:read_topic) { Fabricate(:post).topic }
|
||||
|
||||
before do
|
||||
unread_post = Fabricate(:post, topic: unread_topic)
|
||||
read_post = Fabricate(:post, topic: read_topic)
|
||||
|
||||
TopicUser.change(
|
||||
user.id,
|
||||
unread_topic.id,
|
||||
notification_level: TopicUser.notification_levels[:tracking],
|
||||
)
|
||||
TopicUser.change(
|
||||
user.id,
|
||||
read_topic.id,
|
||||
notification_level: TopicUser.notification_levels[:tracking],
|
||||
)
|
||||
TopicUser.update_last_read(user, unread_topic.id, unread_post.post_number - 1, 1, 1)
|
||||
TopicUser.update_last_read(user, read_topic.id, read_post.post_number, 1, 1)
|
||||
end
|
||||
|
||||
it "includes unread and new topics for the user" do
|
||||
expect(TopicQuery.new(user).new_and_unread_results.pluck(:id)).to contain_exactly(
|
||||
unread_topic.id,
|
||||
new_topic.id,
|
||||
)
|
||||
end
|
||||
|
||||
it "doesn't include deleted topics" do
|
||||
unread_topic.trash!
|
||||
expect(TopicQuery.new(user).new_and_unread_results.pluck(:id)).to contain_exactly(
|
||||
new_topic.id,
|
||||
)
|
||||
end
|
||||
|
||||
it "doesn't include muted topics with unread posts" do
|
||||
TopicUser.change(
|
||||
user.id,
|
||||
unread_topic.id,
|
||||
notification_level: TopicUser.notification_levels[:muted],
|
||||
)
|
||||
expect(TopicQuery.new(user).new_and_unread_results.pluck(:id)).to contain_exactly(
|
||||
new_topic.id,
|
||||
)
|
||||
end
|
||||
|
||||
it "doesn't include muted new topics" do
|
||||
TopicUser.change(
|
||||
user.id,
|
||||
new_topic.id,
|
||||
notification_level: TopicUser.notification_levels[:muted],
|
||||
)
|
||||
expect(TopicQuery.new(user).new_and_unread_results.pluck(:id)).to contain_exactly(
|
||||
unread_topic.id,
|
||||
)
|
||||
end
|
||||
|
||||
it "doesn't include new topics in muted category" do
|
||||
CategoryUser.create!(
|
||||
user_id: user.id,
|
||||
category_id: new_topic.category.id,
|
||||
notification_level: CategoryUser.notification_levels[:muted],
|
||||
)
|
||||
expect(TopicQuery.new(user).new_and_unread_results.pluck(:id)).to contain_exactly(
|
||||
unread_topic.id,
|
||||
)
|
||||
end
|
||||
|
||||
it "includes unread and trakced topics even if they're in a muted category" do
|
||||
new_topic.update!(category: Fabricate(:category))
|
||||
CategoryUser.create!(
|
||||
user_id: user.id,
|
||||
category_id: unread_topic.category.id,
|
||||
notification_level: CategoryUser.notification_levels[:muted],
|
||||
)
|
||||
expect(TopicQuery.new(user).new_and_unread_results.pluck(:id)).to contain_exactly(
|
||||
unread_topic.id,
|
||||
new_topic.id,
|
||||
)
|
||||
end
|
||||
|
||||
it "doesn't include new topics that have a muted tag(s)" do
|
||||
SiteSetting.tagging_enabled = true
|
||||
|
||||
tag = Fabricate(:tag)
|
||||
new_topic.tags << tag
|
||||
new_topic.save!
|
||||
|
||||
TagUser.create!(
|
||||
tag_id: tag.id,
|
||||
user_id: user.id,
|
||||
notification_level: NotificationLevels.all[:muted],
|
||||
)
|
||||
expect(TopicQuery.new(user).new_and_unread_results.pluck(:id)).to contain_exactly(
|
||||
unread_topic.id,
|
||||
)
|
||||
end
|
||||
|
||||
it "includes unread and tracked topics even if they have a muted tag(s)" do
|
||||
SiteSetting.tagging_enabled = true
|
||||
|
||||
tag = Fabricate(:tag)
|
||||
unread_topic.tags << tag
|
||||
unread_topic.save!
|
||||
|
||||
TagUser.create!(
|
||||
tag_id: tag.id,
|
||||
user_id: user.id,
|
||||
notification_level: NotificationLevels.all[:muted],
|
||||
)
|
||||
expect(TopicQuery.new(user).new_and_unread_results.pluck(:id)).to contain_exactly(
|
||||
unread_topic.id,
|
||||
new_topic.id,
|
||||
)
|
||||
end
|
||||
|
||||
it "doesn't include topics in restricted categories that user cannot access" do
|
||||
category = Fabricate(:category_with_definition)
|
||||
group = Fabricate(:group)
|
||||
category.set_permissions(group => :full)
|
||||
category.save!
|
||||
|
||||
unread_topic.update!(category: category)
|
||||
new_topic.update!(category: category)
|
||||
|
||||
expect(TopicQuery.new(user).new_and_unread_results.pluck(:id)).to be_blank
|
||||
end
|
||||
|
||||
it "doesn't include dismissed topics" do
|
||||
DismissedTopicUser.create!(
|
||||
user_id: user.id,
|
||||
topic_id: new_topic.id,
|
||||
created_at: Time.zone.now,
|
||||
)
|
||||
expect(TopicQuery.new(user).new_and_unread_results.pluck(:id)).to contain_exactly(
|
||||
unread_topic.id,
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue
Block a user