diff --git a/app/models/topic_hot_score.rb b/app/models/topic_hot_score.rb index bb71a8ab1b3..a2f8c6d9b85 100644 --- a/app/models/topic_hot_score.rb +++ b/app/models/topic_hot_score.rb @@ -48,7 +48,9 @@ class TopicHotScore < ActiveRecord::Base AND topics.deleted_at IS NULL AND topics.archetype <> :private_message AND topics.created_at <= :now - ORDER BY topics.bumped_at desc + ORDER BY + CASE WHEN topics.pinned_at IS NOT NULL THEN 0 ELSE 1 END ASC, + topics.bumped_at desc LIMIT :max SQL diff --git a/lib/topic_query.rb b/lib/topic_query.rb index 5a05f102d7b..021a351ce99 100644 --- a/lib/topic_query.rb +++ b/lib/topic_query.rb @@ -339,7 +339,7 @@ class TopicQuery end def list_hot - create_list(:hot, unordered: true) do |topics| + create_list(:hot, unordered: true, prioritize_pinned: true) do |topics| topics = remove_muted_topics(topics, user) topics = remove_muted_categories(topics, user, exclude: options[:category]) TopicQuery.remove_muted_tags(topics, user, options) @@ -506,10 +506,12 @@ class TopicQuery DiscoursePluginRegistry.apply_modifier(:topic_query_create_list_topics, topics, options, self) options = options.merge(@options) - if %w[activity default].include?(options[:order] || "activity") && !options[:unordered] && - filter != :private_messages - topics = prioritize_pinned_topics(topics, options) - end + + apply_pinning = filter != :private_messages + apply_pinning &&= %w[activity default].include?(options[:order] || "activity") + apply_pinning &&= !options[:unordered] || options[:prioritize_pinned] + + topics = prioritize_pinned_topics(topics, options) if apply_pinning topics = topics.to_a diff --git a/spec/lib/topic_query_spec.rb b/spec/lib/topic_query_spec.rb index e03dd412692..77b69e4525f 100644 --- a/spec/lib/topic_query_spec.rb +++ b/spec/lib/topic_query_spec.rb @@ -76,6 +76,25 @@ RSpec.describe TopicQuery do end describe "#list_hot" do + it "keeps pinned topics on top" do + pinned_topic = + Fabricate( + :topic, + created_at: 1.hour.ago, + pinned_at: 1.hour.ago, + pinned_globally: true, + like_count: 1, + ) + _topic = Fabricate(:topic, created_at: 5.minute.ago, like_count: 100) + topic = Fabricate(:topic, created_at: 1.minute.ago, like_count: 100) + + # pinned topic is older so generally it would not hit the batch without + # extra special logic + TopicHotScore.update_scores(2) + + expect(TopicQuery.new(nil).list_hot.topics.map(&:id)).to eq([pinned_topic.id, topic.id]) + end + it "excludes muted categories and topics" do muted_category = Fabricate(:category) muted_topic = Fabricate(:topic, category: muted_category)