2011-07-09 11:25:01 +00:00
|
|
|
# Redmine - project management software
|
2014-01-29 22:45:39 +00:00
|
|
|
# Copyright (C) 2006-2014 Jean-Philippe Lang
|
2007-04-30 08:52:39 +00:00
|
|
|
#
|
|
|
|
|
# This program is free software; you can redistribute it and/or
|
|
|
|
|
# modify it under the terms of the GNU General Public License
|
|
|
|
|
# as published by the Free Software Foundation; either version 2
|
|
|
|
|
# of the License, or (at your option) any later version.
|
2011-08-30 14:11:21 +00:00
|
|
|
#
|
2007-04-30 08:52:39 +00:00
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
# GNU General Public License for more details.
|
2011-08-30 14:11:21 +00:00
|
|
|
#
|
2007-04-30 08:52:39 +00:00
|
|
|
# You should have received a copy of the GNU General Public License
|
|
|
|
|
# along with this program; if not, write to the Free Software
|
|
|
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
|
|
|
|
|
class SearchController < ApplicationController
|
2008-03-12 20:50:48 +00:00
|
|
|
before_filter :find_optional_project
|
2007-04-30 08:52:39 +00:00
|
|
|
|
|
|
|
|
def index
|
|
|
|
|
@question = params[:q] || ""
|
|
|
|
|
@question.strip!
|
2011-07-09 11:25:01 +00:00
|
|
|
@all_words = params[:all_words] ? params[:all_words].present? : true
|
|
|
|
|
@titles_only = params[:titles_only] ? params[:titles_only].present? : false
|
2011-08-30 14:11:21 +00:00
|
|
|
|
2008-05-18 16:15:22 +00:00
|
|
|
projects_to_search =
|
2008-05-20 20:31:04 +00:00
|
|
|
case params[:scope]
|
2008-05-18 16:15:22 +00:00
|
|
|
when 'all'
|
|
|
|
|
nil
|
|
|
|
|
when 'my_projects'
|
|
|
|
|
User.current.memberships.collect(&:project)
|
2008-05-20 20:31:04 +00:00
|
|
|
when 'subprojects'
|
2014-10-22 17:37:16 +00:00
|
|
|
@project ? (@project.self_and_descendants.active.to_a) : nil
|
2008-05-18 16:15:22 +00:00
|
|
|
else
|
|
|
|
|
@project
|
|
|
|
|
end
|
2011-08-30 14:11:21 +00:00
|
|
|
|
2007-04-30 08:52:39 +00:00
|
|
|
# quick jump to an issue
|
2012-12-03 21:52:32 +00:00
|
|
|
if (m = @question.match(/^#?(\d+)$/)) && (issue = Issue.visible.find_by_id(m[1].to_i))
|
|
|
|
|
redirect_to issue_path(issue)
|
2007-04-30 08:52:39 +00:00
|
|
|
return
|
|
|
|
|
end
|
2011-08-30 14:11:21 +00:00
|
|
|
|
2010-02-17 20:05:51 +00:00
|
|
|
@object_types = Redmine::Search.available_search_types.dup
|
2008-05-18 16:15:22 +00:00
|
|
|
if projects_to_search.is_a? Project
|
|
|
|
|
# don't search projects
|
|
|
|
|
@object_types.delete('projects')
|
2007-09-24 17:46:25 +00:00
|
|
|
# only show what the user is allowed to view
|
2008-05-18 16:15:22 +00:00
|
|
|
@object_types = @object_types.select {|o| User.current.allowed_to?("view_#{o}".to_sym, projects_to_search)}
|
2007-09-24 17:46:25 +00:00
|
|
|
end
|
2011-08-30 14:11:21 +00:00
|
|
|
|
2008-05-18 16:15:22 +00:00
|
|
|
@scope = @object_types.select {|t| params[t]}
|
|
|
|
|
@scope = @object_types if @scope.empty?
|
2011-08-30 14:11:21 +00:00
|
|
|
|
2007-11-29 18:33:42 +00:00
|
|
|
# extract tokens from the question
|
|
|
|
|
# eg. hello "bye bye" => ["hello", "bye bye"]
|
|
|
|
|
@tokens = @question.scan(%r{((\s|^)"[\s\w]+"(\s|$)|\S+)}).collect {|m| m.first.gsub(%r{(^\s*"\s*|\s*"\s*$)}, '')}
|
2010-01-10 14:15:12 +00:00
|
|
|
# tokens must be at least 2 characters long
|
|
|
|
|
@tokens = @tokens.uniq.select {|w| w.length > 1 }
|
2011-08-30 14:11:21 +00:00
|
|
|
|
2007-04-30 08:52:39 +00:00
|
|
|
if !@tokens.empty?
|
|
|
|
|
# no more than 5 tokens to search for
|
2011-08-30 14:11:21 +00:00
|
|
|
@tokens.slice! 5..-1 if @tokens.size > 5
|
|
|
|
|
|
2007-09-27 17:28:22 +00:00
|
|
|
limit = 10
|
2014-12-12 20:49:31 +00:00
|
|
|
|
|
|
|
|
@result_count = 0
|
|
|
|
|
@result_count_by_type = Hash.new {|h,k| h[k] = 0}
|
|
|
|
|
ranks_and_ids = []
|
|
|
|
|
|
|
|
|
|
# get all the results ranks and ids
|
|
|
|
|
@scope.each do |scope|
|
|
|
|
|
klass = scope.singularize.camelcase.constantize
|
|
|
|
|
ranks_and_ids_in_scope = klass.search_result_ranks_and_ids(@tokens, User.current, projects_to_search,
|
2008-05-18 16:15:22 +00:00
|
|
|
:all_words => @all_words,
|
2014-12-12 20:49:31 +00:00
|
|
|
:titles_only => @titles_only
|
|
|
|
|
)
|
|
|
|
|
@result_count_by_type[scope] += ranks_and_ids_in_scope.size
|
|
|
|
|
@result_count += ranks_and_ids_in_scope.size
|
|
|
|
|
ranks_and_ids += ranks_and_ids_in_scope.map {|r| [scope, r]}
|
2008-05-18 16:15:22 +00:00
|
|
|
end
|
2014-12-12 20:49:31 +00:00
|
|
|
@result_pages = Paginator.new @result_count, limit, params['page']
|
|
|
|
|
|
|
|
|
|
# sort results, higher rank and id first
|
|
|
|
|
ranks_and_ids.sort! {|a,b| b.last <=> a.last }
|
|
|
|
|
ranks_and_ids = ranks_and_ids[@result_pages.offset, limit] || []
|
|
|
|
|
|
|
|
|
|
# load the results to display
|
|
|
|
|
results_by_scope = Hash.new {|h,k| h[k] = []}
|
|
|
|
|
ranks_and_ids.group_by(&:first).each do |scope, rs|
|
|
|
|
|
klass = scope.singularize.camelcase.constantize
|
|
|
|
|
results_by_scope[scope] += klass.search_results_from_ids(rs.map(&:last).map(&:last))
|
2007-04-30 08:52:39 +00:00
|
|
|
end
|
2014-12-12 20:49:31 +00:00
|
|
|
|
|
|
|
|
@results = ranks_and_ids.map do |scope, r|
|
|
|
|
|
results_by_scope[scope].detect {|record| record.id == r.last}
|
|
|
|
|
end.compact
|
2007-04-30 08:52:39 +00:00
|
|
|
else
|
|
|
|
|
@question = ""
|
|
|
|
|
end
|
2007-09-27 17:28:22 +00:00
|
|
|
render :layout => false if request.xhr?
|
2007-04-30 08:52:39 +00:00
|
|
|
end
|
|
|
|
|
|
2011-08-30 14:11:21 +00:00
|
|
|
private
|
2008-03-12 20:50:48 +00:00
|
|
|
def find_optional_project
|
|
|
|
|
return true unless params[:id]
|
2007-04-30 08:52:39 +00:00
|
|
|
@project = Project.find(params[:id])
|
2008-03-12 20:50:48 +00:00
|
|
|
check_project_privacy
|
2007-04-30 08:52:39 +00:00
|
|
|
rescue ActiveRecord::RecordNotFound
|
|
|
|
|
render_404
|
|
|
|
|
end
|
|
|
|
|
end
|