From ab54a616c13b2899d0f61d110a9b9301c0038de1 Mon Sep 17 00:00:00 2001 From: Alan Guo Xiang Tan Date: Thu, 6 Apr 2023 10:13:02 +0800 Subject: [PATCH] DEV: Introduce `in:pinned` filter for experimental `/filter` route (#20974) This commit adds support for the `in:pinned` filter to the topics filtering query language. When the filter is present, it will filter for topics where `Topic#pinned_until` is greater than `Topic#pinned_at`. --- lib/topics_filter.rb | 14 ++++++++++++++ spec/lib/topics_filter_spec.rb | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/lib/topics_filter.rb b/lib/topics_filter.rb index 84cd147aacf..c9222168406 100644 --- a/lib/topics_filter.rb +++ b/lib/topics_filter.rb @@ -14,6 +14,8 @@ class TopicsFilter /(?[-=])?(?\w+):(?[^\s]+)/, ) do |key_prefix, key, value| case key + when "in" + @scope = filter_state(state: value) when "status" @scope = filter_status(status: value) when "tags" @@ -84,6 +86,18 @@ class TopicsFilter private + def filter_state(state:) + case state + when "pinned" + @scope.where( + "topics.pinned_at IS NOT NULL AND topics.pinned_until > topics.pinned_at AND ? < topics.pinned_until", + Time.zone.now, + ) + else + @scope + end + end + def filter_categories(category_slugs:, exclude_subcategories: false, or_clause: false) category_ids = Category.ids_from_slugs(category_slugs) diff --git a/spec/lib/topics_filter_spec.rb b/spec/lib/topics_filter_spec.rb index fa0c55f9db2..7471669077b 100644 --- a/spec/lib/topics_filter_spec.rb +++ b/spec/lib/topics_filter_spec.rb @@ -24,6 +24,40 @@ RSpec.describe TopicsFilter do end end + describe "when filtering with the `in` filter" do + fab!(:topic) { Fabricate(:topic) } + + fab!(:pinned_topic) do + Fabricate(:topic, pinned_at: Time.zone.now, pinned_until: 1.hour.from_now) + end + + fab!(:expired_pinned_topic) do + Fabricate(:topic, pinned_at: 2.hour.ago, pinned_until: 1.hour.ago) + end + + describe "when query string is `in:pinned`" do + it "should return topics that are pinned" do + expect( + TopicsFilter + .new(guardian: Guardian.new) + .filter_from_query_string("in:pinned") + .pluck(:id), + ).to contain_exactly(pinned_topic.id) + end + + it "should not return pinned topics that have expired" do + freeze_time(2.hours.from_now) do + expect( + TopicsFilter + .new(guardian: Guardian.new) + .filter_from_query_string("in:pinned") + .pluck(:id), + ).to eq([]) + end + end + end + end + describe "when filtering by categories" do fab!(:category) { Fabricate(:category, name: "category") }