Use search context for filtering search results by current category or user

This commit is contained in:
Robin Ward 2013-05-24 14:03:45 -04:00
parent f4640e3bff
commit bd779834e5
4 changed files with 115 additions and 5 deletions

View File

@ -2,12 +2,39 @@ require_dependency 'search'
class SearchController < ApplicationController
def query
search = Search.new(params[:term],
guardian: guardian,
type_filter: params[:type_filter])
def self.valid_context_types
%w{user topic category}
end
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)
end
end

View File

@ -35,6 +35,7 @@ class Search
@opts = opts || {}
@guardian = @opts[:guardian] || Guardian.new
@search_context = @opts[:search_context]
@limit = Search.per_facet * Search.facets.size
@results = GroupedSearchResults.new(@opts[:type_filter])
end
@ -142,6 +143,19 @@ class Search
.order("topics.bumped_at DESC")
.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?
posts = posts.where("(categories.id IS NULL) OR (NOT categories.secure) OR (categories.id IN (?))", secure_category_ids)
else

View File

@ -233,6 +233,30 @@ describe Search do
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

View File

@ -2,12 +2,14 @@ require 'spec_helper'
describe SearchController do
let(:search_context) { {type: 'user', id: 'eviltrout'} }
it 'performs the query' do
guardian = Guardian.new
Guardian.stubs(:new).returns(guardian)
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)
xhr :get, :query, term: 'test'
@ -24,4 +26,47 @@ describe SearchController do
xhr :get, :query, term: 'test', type_filter: 'topic'
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