From a4bd1806d96d023264004a26b4241dbe75250344 Mon Sep 17 00:00:00 2001 From: Krzysztof Kotlarek Date: Mon, 10 May 2021 08:57:58 +1000 Subject: [PATCH] FEATURE: ability to register custom filters for posts (#12938) Allow plugins to extend TopicView to filter posts --- lib/plugin/instance.rb | 8 ++++++++ lib/topic_view.rb | 13 +++++++++++++ spec/components/topic_view_spec.rb | 23 +++++++++++++++++++++++ spec/requests/topics_controller_spec.rb | 23 +++++++++++++++++++++++ 4 files changed, 67 insertions(+) diff --git a/lib/plugin/instance.rb b/lib/plugin/instance.rb index d8d8e6717c6..380a63e9875 100644 --- a/lib/plugin/instance.rb +++ b/lib/plugin/instance.rb @@ -208,6 +208,14 @@ class Plugin::Instance Search.advanced_filter(trigger, &block) end + # Allows to define TopicView posts filters. Example usage: + # TopicView.advanced_filter do |posts, opts| + # posts.where(wiki: true) + # end + def register_topic_view_posts_filter(trigger, &block) + TopicView.add_custom_filter(trigger, &block) + end + # Allow to eager load additional tables in Search. Useful to avoid N+1 performance problems. # Example usage: # register_search_topic_eager_load do |opts| diff --git a/lib/topic_view.rb b/lib/topic_view.rb index a646aede74a..d56b064c06a 100644 --- a/lib/topic_view.rb +++ b/lib/topic_view.rb @@ -51,6 +51,15 @@ class TopicView wpcf.flatten.uniq end + def self.add_custom_filter(key, &blk) + @custom_filters ||= {} + @custom_filters[key] = blk + end + + def self.custom_filters + @custom_filters || {} + end + def initialize(topic_or_topic_id, user = nil, options = {}) @topic = find_topic(topic_or_topic_id) @user = user @@ -772,6 +781,10 @@ class TopicView @contains_gaps = true end + if @filter.present? && @filter != 'summary' && TopicView.custom_filters[@filter].present? + @filtered_posts = TopicView.custom_filters[@filter].call(@filtered_posts, self) + end + if @best.present? @filtered_posts = @filtered_posts.where('posts.post_type = ?', Post.types[:regular]) @contains_gaps = true diff --git a/spec/components/topic_view_spec.rb b/spec/components/topic_view_spec.rb index d772becfd8e..9db72fd9f90 100644 --- a/spec/components/topic_view_spec.rb +++ b/spec/components/topic_view_spec.rb @@ -55,6 +55,29 @@ describe TopicView do end end + context 'custom filters' do + fab!(:p0) { Fabricate(:post, topic: topic) } + fab!(:p1) { Fabricate(:post, topic: topic, wiki: true) } + + it 'allows to register custom filters' do + tv = TopicView.new(topic.id, evil_trout, { filter: 'wiki' }) + expect(tv.filter_posts({ filter: "wiki" })).to eq([p0, p1]) + + TopicView.add_custom_filter("wiki") do |posts, topic_view| + posts.where(wiki: true) + end + + tv = TopicView.new(topic.id, evil_trout, { filter: 'wiki' }) + expect(tv.filter_posts).to eq([p1]) + + tv = TopicView.new(topic.id, evil_trout, { filter: 'whatever' }) + expect(tv.filter_posts).to eq([p0, p1]) + + ensure + TopicView.instance_variable_set(:@custom_filters, []) + end + end + context "setup_filtered_posts" do describe "filters posts with ignored users" do fab!(:ignored_user) { Fabricate(:ignored_user, user: evil_trout, ignored_user: user) } diff --git a/spec/requests/topics_controller_spec.rb b/spec/requests/topics_controller_spec.rb index d42354c59f6..68a010f6f16 100644 --- a/spec/requests/topics_controller_spec.rb +++ b/spec/requests/topics_controller_spec.rb @@ -2436,6 +2436,29 @@ RSpec.describe TopicsController do expect(body["post_ids"]).to eq([post2.id]) end end + + describe 'custom filters' do + fab!(:post2) { Fabricate(:post, topic: topic, percent_rank: 0.2) } + fab!(:post3) { Fabricate(:post, topic: topic, percent_rank: 0.5) } + it 'should return the right posts' do + TopicView.add_custom_filter("percent") do |posts, topic_view| + posts.where(percent_rank: 0.5) + end + + get "/t/#{topic.id}.json", params: { + post_number: post.post_number, + filter: 'percent' + } + + expect(response.status).to eq(200) + + body = response.parsed_body + + expect(body["post_stream"]["posts"].map { |p| p["id"] }).to eq([post3.id]) + ensure + TopicView.instance_variable_set(:@custom_filters, []) + end + end end end