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