##// END OF EJS Templates
Fixed: 'search titles only' box ignored after one search is done on titles only....
Jean-Philippe Lang -
r1667:aaca2c50e563
parent child
Show More
@@ -1,122 +1,122
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 Redmine
18 module Redmine
19 module Acts
19 module Acts
20 module Searchable
20 module Searchable
21 def self.included(base)
21 def self.included(base)
22 base.extend ClassMethods
22 base.extend ClassMethods
23 end
23 end
24
24
25 module ClassMethods
25 module ClassMethods
26 # Options:
26 # Options:
27 # * :columns - a column or an array of columns to search
27 # * :columns - a column or an array of columns to search
28 # * :project_key - project foreign key (default to project_id)
28 # * :project_key - project foreign key (default to project_id)
29 # * :date_column - name of the datetime column (default to created_on)
29 # * :date_column - name of the datetime column (default to created_on)
30 # * :sort_order - name of the column used to sort results (default to :date_column or created_on)
30 # * :sort_order - name of the column used to sort results (default to :date_column or created_on)
31 # * :permission - permission required to search the model (default to :view_"objects")
31 # * :permission - permission required to search the model (default to :view_"objects")
32 def acts_as_searchable(options = {})
32 def acts_as_searchable(options = {})
33 return if self.included_modules.include?(Redmine::Acts::Searchable::InstanceMethods)
33 return if self.included_modules.include?(Redmine::Acts::Searchable::InstanceMethods)
34
34
35 cattr_accessor :searchable_options
35 cattr_accessor :searchable_options
36 self.searchable_options = options
36 self.searchable_options = options
37
37
38 if searchable_options[:columns].nil?
38 if searchable_options[:columns].nil?
39 raise 'No searchable column defined.'
39 raise 'No searchable column defined.'
40 elsif !searchable_options[:columns].is_a?(Array)
40 elsif !searchable_options[:columns].is_a?(Array)
41 searchable_options[:columns] = [] << searchable_options[:columns]
41 searchable_options[:columns] = [] << searchable_options[:columns]
42 end
42 end
43
43
44 searchable_options[:project_key] ||= "#{table_name}.project_id"
44 searchable_options[:project_key] ||= "#{table_name}.project_id"
45 searchable_options[:date_column] ||= "#{table_name}.created_on"
45 searchable_options[:date_column] ||= "#{table_name}.created_on"
46 searchable_options[:order_column] ||= searchable_options[:date_column]
46 searchable_options[:order_column] ||= searchable_options[:date_column]
47
47
48 # Permission needed to search this model
48 # Permission needed to search this model
49 searchable_options[:permission] = "view_#{self.name.underscore.pluralize}".to_sym unless searchable_options.has_key?(:permission)
49 searchable_options[:permission] = "view_#{self.name.underscore.pluralize}".to_sym unless searchable_options.has_key?(:permission)
50
50
51 # Should we search custom fields on this model ?
51 # Should we search custom fields on this model ?
52 searchable_options[:search_custom_fields] = !reflect_on_association(:custom_values).nil?
52 searchable_options[:search_custom_fields] = !reflect_on_association(:custom_values).nil?
53
53
54 send :include, Redmine::Acts::Searchable::InstanceMethods
54 send :include, Redmine::Acts::Searchable::InstanceMethods
55 end
55 end
56 end
56 end
57
57
58 module InstanceMethods
58 module InstanceMethods
59 def self.included(base)
59 def self.included(base)
60 base.extend ClassMethods
60 base.extend ClassMethods
61 end
61 end
62
62
63 module ClassMethods
63 module ClassMethods
64 # Searches the model for the given tokens
64 # Searches the model for the given tokens
65 # projects argument can be either nil (will search all projects), a project or an array of projects
65 # projects argument can be either nil (will search all projects), a project or an array of projects
66 # Returns the results and the results count
66 # Returns the results and the results count
67 def search(tokens, projects=nil, options={})
67 def search(tokens, projects=nil, options={})
68 tokens = [] << tokens unless tokens.is_a?(Array)
68 tokens = [] << tokens unless tokens.is_a?(Array)
69 projects = [] << projects unless projects.nil? || projects.is_a?(Array)
69 projects = [] << projects unless projects.nil? || projects.is_a?(Array)
70
70
71 find_options = {:include => searchable_options[:include]}
71 find_options = {:include => searchable_options[:include]}
72 find_options[:order] = "#{searchable_options[:order_column]} " + (options[:before] ? 'DESC' : 'ASC')
72 find_options[:order] = "#{searchable_options[:order_column]} " + (options[:before] ? 'DESC' : 'ASC')
73
73
74 limit_options = {}
74 limit_options = {}
75 limit_options[:limit] = options[:limit] if options[:limit]
75 limit_options[:limit] = options[:limit] if options[:limit]
76 if options[:offset]
76 if options[:offset]
77 limit_options[:conditions] = "(#{searchable_options[:date_column]} " + (options[:before] ? '<' : '>') + "'#{connection.quoted_date(options[:offset])}')"
77 limit_options[:conditions] = "(#{searchable_options[:date_column]} " + (options[:before] ? '<' : '>') + "'#{connection.quoted_date(options[:offset])}')"
78 end
78 end
79
79
80 columns = searchable_options[:columns]
80 columns = searchable_options[:columns]
81 columns.slice!(1..-1) if options[:titles_only]
81 columns = columns[0..0] if options[:titles_only]
82
82
83 token_clauses = columns.collect {|column| "(LOWER(#{column}) LIKE ?)"}
83 token_clauses = columns.collect {|column| "(LOWER(#{column}) LIKE ?)"}
84
84
85 if !options[:titles_only] && searchable_options[:search_custom_fields]
85 if !options[:titles_only] && searchable_options[:search_custom_fields]
86 searchable_custom_field_ids = CustomField.find(:all,
86 searchable_custom_field_ids = CustomField.find(:all,
87 :select => 'id',
87 :select => 'id',
88 :conditions => { :type => "#{self.name}CustomField",
88 :conditions => { :type => "#{self.name}CustomField",
89 :searchable => true }).collect(&:id)
89 :searchable => true }).collect(&:id)
90 if searchable_custom_field_ids.any?
90 if searchable_custom_field_ids.any?
91 custom_field_sql = "#{table_name}.id IN (SELECT customized_id FROM #{CustomValue.table_name}" +
91 custom_field_sql = "#{table_name}.id IN (SELECT customized_id FROM #{CustomValue.table_name}" +
92 " WHERE customized_type='#{self.name}' AND customized_id=#{table_name}.id AND LOWER(value) LIKE ?" +
92 " WHERE customized_type='#{self.name}' AND customized_id=#{table_name}.id AND LOWER(value) LIKE ?" +
93 " AND #{CustomValue.table_name}.custom_field_id IN (#{searchable_custom_field_ids.join(',')}))"
93 " AND #{CustomValue.table_name}.custom_field_id IN (#{searchable_custom_field_ids.join(',')}))"
94 token_clauses << custom_field_sql
94 token_clauses << custom_field_sql
95 end
95 end
96 end
96 end
97
97
98 sql = (['(' + token_clauses.join(' OR ') + ')'] * tokens.size).join(options[:all_words] ? ' AND ' : ' OR ')
98 sql = (['(' + token_clauses.join(' OR ') + ')'] * tokens.size).join(options[:all_words] ? ' AND ' : ' OR ')
99
99
100 find_options[:conditions] = [sql, * (tokens * token_clauses.size).sort]
100 find_options[:conditions] = [sql, * (tokens * token_clauses.size).sort]
101
101
102 project_conditions = []
102 project_conditions = []
103 project_conditions << (searchable_options[:permission].nil? ? Project.visible_by(User.current) :
103 project_conditions << (searchable_options[:permission].nil? ? Project.visible_by(User.current) :
104 Project.allowed_to_condition(User.current, searchable_options[:permission]))
104 Project.allowed_to_condition(User.current, searchable_options[:permission]))
105 project_conditions << "#{searchable_options[:project_key]} IN (#{projects.collect(&:id).join(',')})" unless projects.nil?
105 project_conditions << "#{searchable_options[:project_key]} IN (#{projects.collect(&:id).join(',')})" unless projects.nil?
106
106
107 results = []
107 results = []
108 results_count = 0
108 results_count = 0
109
109
110 with_scope(:find => {:conditions => project_conditions.join(' AND ')}) do
110 with_scope(:find => {:conditions => project_conditions.join(' AND ')}) do
111 with_scope(:find => find_options) do
111 with_scope(:find => find_options) do
112 results_count = count(:all)
112 results_count = count(:all)
113 results = find(:all, limit_options)
113 results = find(:all, limit_options)
114 end
114 end
115 end
115 end
116 [results, results_count]
116 [results, results_count]
117 end
117 end
118 end
118 end
119 end
119 end
120 end
120 end
121 end
121 end
122 end
122 end
General Comments 0
You need to be logged in to leave comments. Login now