##// END OF EJS Templates
Issue notes are now included in search....
Jean-Philippe Lang -
r694:8dcc04124482
parent child
Show More
@@ -1,81 +1,85
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class SearchController < ApplicationController
18 class SearchController < ApplicationController
19 layout 'base'
19 layout 'base'
20
20
21 helper :messages
21 helper :messages
22 include MessagesHelper
22 include MessagesHelper
23
23
24 def index
24 def index
25 @question = params[:q] || ""
25 @question = params[:q] || ""
26 @question.strip!
26 @question.strip!
27 @all_words = params[:all_words] || (params[:submit] ? false : true)
27 @all_words = params[:all_words] || (params[:submit] ? false : true)
28 @scope = params[:scope] || (params[:submit] ? [] : %w(projects issues changesets news documents wiki messages) )
28 @scope = params[:scope] || (params[:submit] ? [] : %w(projects issues changesets news documents wiki messages) )
29
29
30 # quick jump to an issue
30 # quick jump to an issue
31 if @scope.include?('issues') && @question.match(/^#?(\d+)$/) && Issue.find_by_id($1, :include => :project, :conditions => Project.visible_by(logged_in_user))
31 if @scope.include?('issues') && @question.match(/^#?(\d+)$/) && Issue.find_by_id($1, :include => :project, :conditions => Project.visible_by(logged_in_user))
32 redirect_to :controller => "issues", :action => "show", :id => $1
32 redirect_to :controller => "issues", :action => "show", :id => $1
33 return
33 return
34 end
34 end
35
35
36 if params[:id]
36 if params[:id]
37 find_project
37 find_project
38 return unless check_project_privacy
38 return unless check_project_privacy
39 end
39 end
40
40
41 # tokens must be at least 3 character long
41 # tokens must be at least 3 character long
42 @tokens = @question.split.uniq.select {|w| w.length > 2 }
42 @tokens = @question.split.uniq.select {|w| w.length > 2 }
43
43
44 if !@tokens.empty?
44 if !@tokens.empty?
45 # no more than 5 tokens to search for
45 # no more than 5 tokens to search for
46 @tokens.slice! 5..-1 if @tokens.size > 5
46 @tokens.slice! 5..-1 if @tokens.size > 5
47 # strings used in sql like statement
47 # strings used in sql like statement
48 like_tokens = @tokens.collect {|w| "%#{w.downcase}%"}
48 like_tokens = @tokens.collect {|w| "%#{w.downcase}%"}
49 operator = @all_words ? " AND " : " OR "
49 operator = @all_words ? " AND " : " OR "
50 limit = 10
50 limit = 10
51 @results = []
51 @results = []
52 if @project
52 if @project
53 @results += @project.issues.find(:all, :limit => limit, :include => :author, :conditions => [ (["(LOWER(subject) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @scope.include? 'issues'
53 @results += @project.issues.find(:all, :limit => limit, :include => :author, :conditions => [ (["(LOWER(subject) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @scope.include? 'issues'
54 Journal.with_scope :find => {:conditions => ["#{Issue.table_name}.project_id = ?", @project.id]} do
55 @results += Journal.find(:all, :include => :issue, :limit => limit, :conditions => [ (["(LOWER(notes) like ? OR LOWER(notes) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ).collect(&:issue) if @scope.include? 'issues'
56 end
57 @results.uniq!
54 @results += @project.news.find(:all, :limit => limit, :conditions => [ (["(LOWER(title) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort], :include => :author ) if @scope.include? 'news'
58 @results += @project.news.find(:all, :limit => limit, :conditions => [ (["(LOWER(title) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort], :include => :author ) if @scope.include? 'news'
55 @results += @project.documents.find(:all, :limit => limit, :conditions => [ (["(LOWER(title) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @scope.include? 'documents'
59 @results += @project.documents.find(:all, :limit => limit, :conditions => [ (["(LOWER(title) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @scope.include? 'documents'
56 @results += @project.wiki.pages.find(:all, :limit => limit, :include => :content, :conditions => [ (["(LOWER(title) like ? OR LOWER(text) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @project.wiki && @scope.include?('wiki')
60 @results += @project.wiki.pages.find(:all, :limit => limit, :include => :content, :conditions => [ (["(LOWER(title) like ? OR LOWER(text) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @project.wiki && @scope.include?('wiki')
57 @results += @project.repository.changesets.find(:all, :limit => limit, :conditions => [ (["(LOWER(comments) like ?)"] * like_tokens.size).join(operator), * (like_tokens).sort] ) if @project.repository && @scope.include?('changesets')
61 @results += @project.repository.changesets.find(:all, :limit => limit, :conditions => [ (["(LOWER(comments) like ?)"] * like_tokens.size).join(operator), * (like_tokens).sort] ) if @project.repository && @scope.include?('changesets')
58 Message.with_scope :find => {:conditions => ["#{Board.table_name}.project_id = ?", @project.id]} do
62 Message.with_scope :find => {:conditions => ["#{Board.table_name}.project_id = ?", @project.id]} do
59 @results += Message.find(:all, :include => :board, :limit => limit, :conditions => [ (["(LOWER(subject) like ? OR LOWER(content) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @scope.include? 'messages'
63 @results += Message.find(:all, :include => :board, :limit => limit, :conditions => [ (["(LOWER(subject) like ? OR LOWER(content) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @scope.include? 'messages'
60 end
64 end
61 else
65 else
62 Project.with_scope(:find => {:conditions => Project.visible_by(logged_in_user)}) do
66 Project.with_scope(:find => {:conditions => Project.visible_by(logged_in_user)}) do
63 @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'
67 @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'
64 end
68 end
65 # if only one project is found, user is redirected to its overview
69 # if only one project is found, user is redirected to its overview
66 redirect_to :controller => 'projects', :action => 'show', :id => @results.first and return if @results.size == 1
70 redirect_to :controller => 'projects', :action => 'show', :id => @results.first and return if @results.size == 1
67 end
71 end
68 @question = @tokens.join(" ")
72 @question = @tokens.join(" ")
69 else
73 else
70 @question = ""
74 @question = ""
71 end
75 end
72 end
76 end
73
77
74 private
78 private
75 def find_project
79 def find_project
76 @project = Project.find(params[:id])
80 @project = Project.find(params[:id])
77 @html_title = @project.name
81 @html_title = @project.name
78 rescue ActiveRecord::RecordNotFound
82 rescue ActiveRecord::RecordNotFound
79 render_404
83 render_404
80 end
84 end
81 end
85 end
@@ -1,28 +1,33
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 module SearchHelper
18 module SearchHelper
19 def highlight_tokens(text, tokens)
19 def highlight_tokens(text, tokens)
20 return text unless tokens && !tokens.empty?
20 return text unless tokens && !tokens.empty?
21 regexp = Regexp.new "(#{tokens.join('|')})", Regexp::IGNORECASE
21 regexp = Regexp.new "(#{tokens.join('|')})", Regexp::IGNORECASE
22 result = ''
22 result = ''
23 text.split(regexp).each_with_index do |words, i|
23 text.split(regexp).each_with_index do |words, i|
24 result << (i.even? ? (words.length > 100 ? "#{words[0..44]} ... #{words[-45..-1]}" : words) : content_tag('span', words, :class => 'highlight'))
24 if result.length > 1200
25 # maximum length of the preview reached
26 result << '...'
27 break
28 end
29 result << (i.even? ? h(words.length > 100 ? "#{words[0..44]} ... #{words[-45..-1]}" : words) : content_tag('span', h(words), :class => 'highlight'))
25 end
30 end
26 result
31 result
27 end
32 end
28 end
33 end
General Comments 0
You need to be logged in to leave comments. Login now