diff --git a/app/controllers/list_controller.rb b/app/controllers/list_controller.rb index f5f2f8fb01f..66487193800 100644 --- a/app/controllers/list_controller.rb +++ b/app/controllers/list_controller.rb @@ -277,27 +277,15 @@ class ListController < ApplicationController end def build_topic_list_options - options = { - page: params[:page], - topic_ids: param_to_integer_list(:topic_ids), - exclude_category_ids: params[:exclude_category_ids], - category: params[:category], - order: params[:order], - ascending: params[:ascending], - min_posts: params[:min_posts], - max_posts: params[:max_posts], - status: params[:status], - filter: params[:filter], - state: params[:state], - search: params[:search], - q: params[:q], - group_name: params[:group_name], - tags: params[:tags], - match_all_tags: params[:match_all_tags], - no_tags: params[:no_tags] - } - options[:no_subcategories] = true if params[:no_subcategories] == 'true' - options[:slow_platform] = true if slow_platform? + options = {} + TopicQuery.valid_options.each do |key| + options[key] = params[key] + end + + # hacky columns get special handling + options[:topic_ids] = param_to_integer_list(:topic_ids) + options[:no_subcategories] = options[:no_subcategories] == 'true' + options[:slow_platform] = slow_platform? options end diff --git a/lib/topic_query.rb b/lib/topic_query.rb index 3da879c6a32..a1a8818dacd 100644 --- a/lib/topic_query.rb +++ b/lib/topic_query.rb @@ -9,30 +9,35 @@ require_dependency 'topic_query_sql' require_dependency 'avatar_lookup' class TopicQuery - VALID_OPTIONS = %i(except_topic_ids - exclude_category_ids - limit - page - per_page - min_posts - max_posts - topic_ids - visible - category - tags - match_all_tags - no_tags - order - ascending - no_subcategories - no_definitions - status - state - search - slow_platform - filter - group_name - q) + + def self.valid_options + @valid_options ||= + %i(except_topic_ids + exclude_category_ids + limit + page + per_page + min_posts + max_posts + topic_ids + visible + category + tags + match_all_tags + no_tags + order + ascending + no_subcategories + no_definitions + status + state + search + slow_platform + filter + group_name + q) + end + # Maps `order` to a columns in `topics` SORTABLE_MAPPING = { @@ -49,8 +54,31 @@ class TopicQuery cattr_accessor :results_filter_callbacks self.results_filter_callbacks = [] + attr_accessor :options, :user, :guardian + + def self.add_custom_filter(key, &blk) + @custom_filters ||= {} + valid_options << key + @custom_filters[key] = blk + end + + def self.remove_custom_filter(key) + @custom_filters.delete(key) + valid_options.delete(key) + @custom_filters = nil if @custom_filters.length == 0 + end + + def self.apply_custom_filters(results, topic_query) + if @custom_filters + @custom_filters.each do |key,filter| + results = filter.call(results, topic_query) + end + end + results + end + def initialize(user=nil, options={}) - options.assert_valid_keys(VALID_OPTIONS) + options.assert_valid_keys(TopicQuery.valid_options) @options = options.dup @user = user @guardian = Guardian.new(@user) @@ -589,6 +617,8 @@ class TopicQuery result = result.where('topics.posts_count <= ?', options[:max_posts]) if options[:max_posts].present? result = result.where('topics.posts_count >= ?', options[:min_posts]) if options[:min_posts].present? + result = TopicQuery.apply_custom_filters(result,self) + @guardian.filter_allowed_categories(result) end diff --git a/spec/components/topic_query_spec.rb b/spec/components/topic_query_spec.rb index 619a080aaec..65b5196a1c3 100644 --- a/spec/components/topic_query_spec.rb +++ b/spec/components/topic_query_spec.rb @@ -40,6 +40,21 @@ describe TopicQuery do end + context "custom filters" do + it "allows custom filters to be applied" do + topic1 = Fabricate(:topic) + _topic2 = Fabricate(:topic) + + TopicQuery.add_custom_filter(:only_topic_id) do |results, topic_query| + results = results.where('topics.id = ?', topic_query.options[:only_topic_id]) + end + + expect(TopicQuery.new(nil, {only_topic_id: topic1.id}).list_latest.topics.map(&:id)).to eq([topic1.id]) + + TopicQuery.remove_custom_filter(:only_topic_id) + end + end + context "list_topics_by" do it "allows users to view their own invisible topics" do