From c92f0b8775fddd4f0ec27e17433fef40298404f8 Mon Sep 17 00:00:00 2001 From: Roman Rizzi Date: Fri, 22 Nov 2019 16:33:10 -0300 Subject: [PATCH] FEATURE: New API to apply custom filters to the review queue (#8392) --- .../discourse/controllers/review-index.js.es6 | 8 ++++-- .../discourse/routes/review-index.js.es6 | 3 ++- .../discourse/templates/review-index.hbs | 2 +- app/controllers/reviewables_controller.rb | 13 +++++----- app/models/reviewable.rb | 25 ++++++++++++++++++- lib/plugin/instance.rb | 9 +++++++ spec/models/reviewable_spec.rb | 25 +++++++++++++++++++ 7 files changed, 74 insertions(+), 11 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/review-index.js.es6 b/app/assets/javascripts/discourse/controllers/review-index.js.es6 index 0c9f090aa43..aeb61d7d61e 100644 --- a/app/assets/javascripts/discourse/controllers/review-index.js.es6 +++ b/app/assets/javascripts/discourse/controllers/review-index.js.es6 @@ -11,7 +11,8 @@ export default Controller.extend({ "username", "from_date", "to_date", - "sort_order" + "sort_order", + "additional_filters" ], type: null, status: "pending", @@ -24,6 +25,7 @@ export default Controller.extend({ from_date: null, to_date: null, sort_order: "priority", + additional_filters: null, init(...args) { this._super(...args); @@ -118,8 +120,10 @@ export default Controller.extend({ username: this.filterUsername, from_date: this.filterFromDate, to_date: this.filterToDate, - sort_order: this.filterSortOrder + sort_order: this.filterSortOrder, + additional_filters: JSON.stringify(this.additionalFilters) }); + this.send("refreshRoute"); }, diff --git a/app/assets/javascripts/discourse/routes/review-index.js.es6 b/app/assets/javascripts/discourse/routes/review-index.js.es6 index 2c08fa8ed5f..3da7513e6d0 100644 --- a/app/assets/javascripts/discourse/routes/review-index.js.es6 +++ b/app/assets/javascripts/discourse/routes/review-index.js.es6 @@ -25,7 +25,8 @@ export default DiscourseRoute.extend({ filterUsername: meta.username, filterFromDate: meta.from_date, filterToDate: meta.to_date, - filterSortOrder: meta.sort_order + filterSortOrder: meta.sort_order, + additionalFilters: meta.additional_filters || {} }); }, diff --git a/app/assets/javascripts/discourse/templates/review-index.hbs b/app/assets/javascripts/discourse/templates/review-index.hbs index 76f2fe20627..277c7723f89 100644 --- a/app/assets/javascripts/discourse/templates/review-index.hbs +++ b/app/assets/javascripts/discourse/templates/review-index.hbs @@ -24,7 +24,7 @@ {{#if filtersExpanded}} - {{plugin-outlet name="above-review-filters" args=(hash model=model)}} + {{plugin-outlet name="above-review-filters" args=(hash model=model additionalFilters=additionalFilters)}}
diff --git a/app/controllers/reviewables_controller.rb b/app/controllers/reviewables_controller.rb index 47d65c1efd3..83738cb21d1 100644 --- a/app/controllers/reviewables_controller.rb +++ b/app/controllers/reviewables_controller.rb @@ -20,18 +20,19 @@ class ReviewablesController < ApplicationController topic_id = params[:topic_id] ? params[:topic_id].to_i : nil category_id = params[:category_id] ? params[:category_id].to_i : nil + custom_keys = Reviewable.custom_filters.map(&:first) + additional_filters = JSON.parse(params.fetch(:additional_filters, {}), symbolize_names: true).slice(*custom_keys) filters = { status: status, category_id: category_id, topic_id: topic_id, - priority: params[:priority], - username: params[:username], - from_date: params[:from_date], - to_date: params[:to_date], - type: params[:type], - sort_order: params[:sort_order] + additional_filters: additional_filters.reject { |_, v| v.blank? } } + %i[priority username from_date to_date type sort_order].each do |filter_key| + filters[filter_key] = params[filter_key] + end + total_rows = Reviewable.list_for(current_user, filters).count reviewables = Reviewable.list_for(current_user, filters.merge(limit: PER_PAGE, offset: offset)).to_a diff --git a/app/models/reviewable.rb b/app/models/reviewable.rb index f8a0398597e..287d5a5f924 100644 --- a/app/models/reviewable.rb +++ b/app/models/reviewable.rb @@ -98,6 +98,18 @@ class Reviewable < ActiveRecord::Base %w[ReviewableFlaggedPost ReviewableQueuedPost ReviewableUser] end + def self.custom_filters + @reviewable_filters ||= [] + end + + def self.add_custom_filter(new_filter) + custom_filters << new_filter + end + + def self.clear_custom_filters! + @reviewable_filters = [] + end + def created_new! self.created_new = true self.topic = target.topic if topic.blank? && target.is_a?(Post) @@ -408,7 +420,8 @@ class Reviewable < ActiveRecord::Base username: nil, sort_order: nil, from_date: nil, - to_date: nil + to_date: nil, + additional_filters: {} ) min_score = Reviewable.min_score_for_priority(priority) @@ -439,6 +452,16 @@ class Reviewable < ActiveRecord::Base result = result.where("created_at >= ?", from_date) if from_date result = result.where("created_at <= ?", to_date) if to_date + if !custom_filters.empty? + result = custom_filters.reduce(result) do |memo, filter| + key = filter.first + filter_query = filter.last + + next(memo) unless additional_filters[key] + filter_query.call(result, additional_filters[key]) + end + end + # If a reviewable doesn't have a target, allow us to filter on who created that reviewable. if user_id result = result.where( diff --git a/lib/plugin/instance.rb b/lib/plugin/instance.rb index 945def58ba3..19024de7a12 100644 --- a/lib/plugin/instance.rb +++ b/lib/plugin/instance.rb @@ -663,6 +663,15 @@ class Plugin::Instance File.exists?(js_file_path) end + # Receives an array with two elements: + # 1. A symbol that represents the name of the value to filter. + # 2. A Proc that takes the existing ActiveRecord::Relation and the value received from the front-end. + def add_custom_reviewable_filter(filter) + reloadable_patch do + Reviewable.add_custom_filter(filter) + end + end + protected def self.js_path diff --git a/spec/models/reviewable_spec.rb b/spec/models/reviewable_spec.rb index 6e8cfa32ce5..84235644b17 100644 --- a/spec/models/reviewable_spec.rb +++ b/spec/models/reviewable_spec.rb @@ -435,4 +435,29 @@ RSpec.describe Reviewable, type: :model do expect(Reviewable.min_score_for_priority).to eq(45.6) end end + + context "custom filters" do + after do + Reviewable.clear_custom_filters! + end + + it 'correctly add a new filter' do + Reviewable.add_custom_filter([:assigned_to, Proc.new { |results, value| results }]) + + expect(Reviewable.custom_filters.size).to eq(1) + end + + it 'applies the custom filter' do + admin = Fabricate(:admin) + first_reviewable = Fabricate(:reviewable) + second_reviewable = Fabricate(:reviewable) + custom_filter = [:target_id, Proc.new { |results, value| results.where(target_id: value) }] + Reviewable.add_custom_filter(custom_filter) + + results = Reviewable.list_for(admin, additional_filters: { target_id: first_reviewable.target_id }) + + expect(results.size).to eq(1) + expect(results.first).to eq first_reviewable + end + end end