2007-04-30 12:52:39 +04:00
# redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang
#
# 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.
#
# 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.
#
# 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
layout 'base'
2007-05-14 21:46:58 +04:00
helper :messages
include MessagesHelper
2007-04-30 12:52:39 +04:00
def index
@question = params [ :q ] || " "
@question . strip!
@all_words = params [ :all_words ] || ( params [ :submit ] ? false : true )
2007-10-15 20:53:39 +04:00
@titles_only = ! params [ :titles_only ] . nil?
2007-04-30 12:52:39 +04:00
2007-09-27 21:28:22 +04:00
offset = nil
begin ; offset = params [ :offset ] . to_time if params [ :offset ] ; rescue ; end
2007-04-30 12:52:39 +04:00
# quick jump to an issue
2007-11-20 18:40:16 +03:00
if @question . match ( / ^ # ?( \ d+)$ / ) && Issue . find_by_id ( $1 , :include = > :project , :conditions = > Project . visible_by ( User . current ) )
2007-04-30 12:52:39 +04:00
redirect_to :controller = > " issues " , :action = > " show " , :id = > $1
return
end
if params [ :id ]
find_project
return unless check_project_privacy
end
2007-09-24 21:46:25 +04:00
if @project
# only show what the user is allowed to view
2007-09-27 21:28:22 +04:00
@object_types = %w( issues news documents changesets wiki_pages messages )
2007-09-24 21:46:25 +04:00
@object_types = @object_types . select { | o | User . current . allowed_to? ( " view_ #{ o } " . to_sym , @project ) }
@scope = @object_types . select { | t | params [ t ] }
@scope = @object_types if @scope . empty?
else
2007-09-24 22:08:24 +04:00
@object_types = @scope = %w( projects )
2007-09-24 21:46:25 +04:00
end
2007-11-29 21:33:42 +03: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*$) } , '' ) }
2007-04-30 12:52:39 +04:00
# tokens must be at least 3 character long
2007-11-29 21:33:42 +03:00
@tokens = @tokens . uniq . select { | w | w . length > 2 }
2007-04-30 12:52:39 +04:00
if ! @tokens . empty?
# no more than 5 tokens to search for
@tokens . slice! 5 .. - 1 if @tokens . size > 5
# strings used in sql like statement
2007-10-15 20:53:39 +04:00
like_tokens = @tokens . collect { | w | " % #{ w . downcase } % " }
2007-04-30 12:52:39 +04:00
@results = [ ]
2007-09-27 21:28:22 +04:00
limit = 10
2007-09-24 21:46:25 +04:00
if @project
2007-09-27 21:28:22 +04:00
@scope . each do | s |
2007-10-15 20:53:39 +04:00
@results += s . singularize . camelcase . constantize . search ( like_tokens , @project ,
:all_words = > @all_words ,
:titles_only = > @titles_only ,
:limit = > ( limit + 1 ) ,
:offset = > offset ,
:before = > params [ :previous ] . nil? )
2007-09-05 23:37:13 +04:00
end
2007-09-27 21:28:22 +04:00
@results = @results . sort { | a , b | b . event_datetime < = > a . event_datetime }
if params [ :previous ] . nil?
@pagination_previous_date = @results [ 0 ] . event_datetime if offset && @results [ 0 ]
if @results . size > limit
@pagination_next_date = @results [ limit - 1 ] . event_datetime
@results = @results [ 0 , limit ]
end
else
@pagination_next_date = @results [ - 1 ] . event_datetime if offset && @results [ - 1 ]
if @results . size > limit
@pagination_previous_date = @results [ - ( limit ) ] . event_datetime
@results = @results [ - ( limit ) , limit ]
end
2007-05-14 21:46:58 +04:00
end
2007-04-30 12:52:39 +04:00
else
2007-10-15 20:53:39 +04:00
operator = @all_words ? ' AND ' : ' OR '
2007-11-20 18:40:16 +03:00
Project . with_scope ( :find = > { :conditions = > Project . visible_by ( User . current ) } ) do
2007-04-30 12:52:39 +04:00
@results += Project . find ( :all , :limit = > limit , :conditions = > [ ( [ " (LOWER(name) like ? OR LOWER(description) like ?) " ] * like_tokens . size ) . join ( operator ) , * ( like_tokens * 2 ) . sort ] ) if @scope . include? 'projects'
end
# if only one project is found, user is redirected to its overview
redirect_to :controller = > 'projects' , :action = > 'show' , :id = > @results . first and return if @results . size == 1
end
else
@question = " "
end
2007-09-27 21:28:22 +04:00
render :layout = > false if request . xhr?
2007-04-30 12:52:39 +04:00
end
private
def find_project
@project = Project . find ( params [ :id ] )
rescue ActiveRecord :: RecordNotFound
render_404
end
end