Use search context for filtering search results by current category or user
This commit is contained in:
parent
f4640e3bff
commit
bd779834e5
|
@ -2,12 +2,39 @@ require_dependency 'search'
|
||||||
|
|
||||||
class SearchController < ApplicationController
|
class SearchController < ApplicationController
|
||||||
|
|
||||||
def query
|
def self.valid_context_types
|
||||||
search = Search.new(params[:term],
|
%w{user topic category}
|
||||||
guardian: guardian,
|
end
|
||||||
type_filter: params[:type_filter])
|
|
||||||
|
|
||||||
|
def query
|
||||||
|
requires_parameter(:term)
|
||||||
|
|
||||||
|
search_args = {guardian: guardian}
|
||||||
|
search_args[:type_filter] = params[:type_filter] if params[:type_filter].present?
|
||||||
|
|
||||||
|
search_context = params[:search_context]
|
||||||
|
if search_context.present?
|
||||||
|
raise Discourse::InvalidParameters.new(:search_context) unless SearchController.valid_context_types.include?(search_context[:type])
|
||||||
|
raise Discourse::InvalidParameters.new(:search_context) if search_context[:id].blank?
|
||||||
|
|
||||||
|
klass = search_context[:type].classify.constantize
|
||||||
|
|
||||||
|
# A user is found by username
|
||||||
|
context_obj = nil
|
||||||
|
if search_context[:type] == 'user'
|
||||||
|
context_obj = klass.where(username: params[:search_context][:id]).first
|
||||||
|
else
|
||||||
|
context_obj = klass.where(id: params[:search_context][:id]).first
|
||||||
|
end
|
||||||
|
|
||||||
|
guardian.ensure_can_see!(context_obj)
|
||||||
|
search_args[:search_context] = context_obj
|
||||||
|
end
|
||||||
|
|
||||||
|
search = Search.new(params[:term], search_args.symbolize_keys)
|
||||||
render_json_dump(search.execute.as_json)
|
render_json_dump(search.execute.as_json)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -35,6 +35,7 @@ class Search
|
||||||
|
|
||||||
@opts = opts || {}
|
@opts = opts || {}
|
||||||
@guardian = @opts[:guardian] || Guardian.new
|
@guardian = @opts[:guardian] || Guardian.new
|
||||||
|
@search_context = @opts[:search_context]
|
||||||
@limit = Search.per_facet * Search.facets.size
|
@limit = Search.per_facet * Search.facets.size
|
||||||
@results = GroupedSearchResults.new(@opts[:type_filter])
|
@results = GroupedSearchResults.new(@opts[:type_filter])
|
||||||
end
|
end
|
||||||
|
@ -142,6 +143,19 @@ class Search
|
||||||
.order("topics.bumped_at DESC")
|
.order("topics.bumped_at DESC")
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
|
|
||||||
|
# Search context post results
|
||||||
|
if @search_context.present?
|
||||||
|
|
||||||
|
if @search_context.is_a?(User)
|
||||||
|
# If the context is a user, restrict posts to that user
|
||||||
|
posts = posts.where(user_id: @search_context.id)
|
||||||
|
elsif @search_context.is_a?(Category)
|
||||||
|
# If the context is a category, restrict posts to that category
|
||||||
|
posts = posts.where('topics.category_id' => @search_context.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
if secure_category_ids.present?
|
if secure_category_ids.present?
|
||||||
posts = posts.where("(categories.id IS NULL) OR (NOT categories.secure) OR (categories.id IN (?))", secure_category_ids)
|
posts = posts.where("(categories.id IS NULL) OR (NOT categories.secure) OR (categories.id IN (?))", secure_category_ids)
|
||||||
else
|
else
|
||||||
|
|
|
@ -233,6 +233,30 @@ describe Search do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'search_context' do
|
||||||
|
|
||||||
|
context 'user as a search context' do
|
||||||
|
let(:search_user) { Search.new('hello', search_context: post.user).execute }
|
||||||
|
let(:search_coding_horror) { Search.new('hello', search_context: Fabricate(:coding_horror)).execute }
|
||||||
|
|
||||||
|
Given!(:post) { Fabricate(:post) }
|
||||||
|
Then { first_of_type(search_user, 'topic')['id'] == post.topic_id }
|
||||||
|
And { first_of_type(search_coding_horror, 'topic').should be_blank }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'category as a search context' do
|
||||||
|
let(:category) { Fabricate(:category) }
|
||||||
|
let(:search_cat) { Search.new('hello', search_context: category).execute }
|
||||||
|
let(:search_other_cat) { Search.new('hello', search_context: Fabricate(:category) ).execute }
|
||||||
|
let(:topic) { Fabricate(:topic, category: category) }
|
||||||
|
|
||||||
|
Given!(:post) { Fabricate(:post, topic: topic, user: topic.user ) }
|
||||||
|
Then { first_of_type(search_cat, 'topic')['id'] == post.topic_id }
|
||||||
|
Then { first_of_type(search_other_cat, 'topic').should be_blank }
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,14 @@ require 'spec_helper'
|
||||||
|
|
||||||
describe SearchController do
|
describe SearchController do
|
||||||
|
|
||||||
|
let(:search_context) { {type: 'user', id: 'eviltrout'} }
|
||||||
|
|
||||||
it 'performs the query' do
|
it 'performs the query' do
|
||||||
guardian = Guardian.new
|
guardian = Guardian.new
|
||||||
Guardian.stubs(:new).returns(guardian)
|
Guardian.stubs(:new).returns(guardian)
|
||||||
|
|
||||||
search = mock()
|
search = mock()
|
||||||
Search.expects(:new).with('test', guardian: guardian, type_filter: nil).returns(search)
|
Search.expects(:new).with('test', guardian: guardian).returns(search)
|
||||||
search.expects(:execute)
|
search.expects(:execute)
|
||||||
|
|
||||||
xhr :get, :query, term: 'test'
|
xhr :get, :query, term: 'test'
|
||||||
|
@ -24,4 +26,47 @@ describe SearchController do
|
||||||
xhr :get, :query, term: 'test', type_filter: 'topic'
|
xhr :get, :query, term: 'test', type_filter: 'topic'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "search context" do
|
||||||
|
|
||||||
|
it "raises an error with an invalid context type" do
|
||||||
|
lambda {
|
||||||
|
xhr :get, :query, term: 'test', search_context: {type: 'security', id: 'hole'}
|
||||||
|
}.should raise_error(Discourse::InvalidParameters)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "raises an error with a missing id" do
|
||||||
|
lambda {
|
||||||
|
xhr :get, :query, term: 'test', search_context: {type: 'user'}
|
||||||
|
}.should raise_error(Discourse::InvalidParameters)
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with a user" do
|
||||||
|
|
||||||
|
let(:user) { Fabricate(:user) }
|
||||||
|
|
||||||
|
it "raises an error if the user can't see the context" do
|
||||||
|
Guardian.any_instance.expects(:can_see?).with(user).returns(false)
|
||||||
|
xhr :get, :query, term: 'test', search_context: {type: 'user', id: user.username}
|
||||||
|
response.should_not be_success
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
it 'performs the query with a search context' do
|
||||||
|
guardian = Guardian.new
|
||||||
|
Guardian.stubs(:new).returns(guardian)
|
||||||
|
|
||||||
|
search = mock()
|
||||||
|
Search.expects(:new).with('test', guardian: guardian, search_context: user).returns(search)
|
||||||
|
search.expects(:execute)
|
||||||
|
|
||||||
|
xhr :get, :query, term: 'test', search_context: {type: 'user', id: user.username}
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue