Mercurial > hg > soundsoftware-site
comparison .svn/pristine/ad/ad9161bbe4944ca1db8ea296d48b7287d41e3113.svn-base @ 1298:4f746d8966dd redmine_2.3_integration
Merge from redmine-2.3 branch to create new branch redmine-2.3-integration
author | Chris Cannam |
---|---|
date | Fri, 14 Jun 2013 09:28:30 +0100 |
parents | 622f24f53b42 |
children |
comparison
equal
deleted
inserted
replaced
1297:0a574315af3e | 1298:4f746d8966dd |
---|---|
1 # Redmine - project management software | |
2 # Copyright (C) 2006-2013 Jean-Philippe Lang | |
3 # | |
4 # This program is free software; you can redistribute it and/or | |
5 # modify it under the terms of the GNU General Public License | |
6 # as published by the Free Software Foundation; either version 2 | |
7 # of the License, or (at your option) any later version. | |
8 # | |
9 # This program is distributed in the hope that it will be useful, | |
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 # GNU General Public License for more details. | |
13 # | |
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 | |
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 | |
18 module Redmine | |
19 module Acts | |
20 module Searchable | |
21 def self.included(base) | |
22 base.extend ClassMethods | |
23 end | |
24 | |
25 module ClassMethods | |
26 # Options: | |
27 # * :columns - a column or an array of columns to search | |
28 # * :project_key - project foreign key (default to project_id) | |
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) | |
31 # * :permission - permission required to search the model (default to :view_"objects") | |
32 def acts_as_searchable(options = {}) | |
33 return if self.included_modules.include?(Redmine::Acts::Searchable::InstanceMethods) | |
34 | |
35 cattr_accessor :searchable_options | |
36 self.searchable_options = options | |
37 | |
38 if searchable_options[:columns].nil? | |
39 raise 'No searchable column defined.' | |
40 elsif !searchable_options[:columns].is_a?(Array) | |
41 searchable_options[:columns] = [] << searchable_options[:columns] | |
42 end | |
43 | |
44 searchable_options[:project_key] ||= "#{table_name}.project_id" | |
45 searchable_options[:date_column] ||= "#{table_name}.created_on" | |
46 searchable_options[:order_column] ||= searchable_options[:date_column] | |
47 | |
48 # Should we search custom fields on this model ? | |
49 searchable_options[:search_custom_fields] = !reflect_on_association(:custom_values).nil? | |
50 | |
51 send :include, Redmine::Acts::Searchable::InstanceMethods | |
52 end | |
53 end | |
54 | |
55 module InstanceMethods | |
56 def self.included(base) | |
57 base.extend ClassMethods | |
58 end | |
59 | |
60 module ClassMethods | |
61 # Searches the model for the given tokens | |
62 # projects argument can be either nil (will search all projects), a project or an array of projects | |
63 # Returns the results and the results count | |
64 def search(tokens, projects=nil, options={}) | |
65 if projects.is_a?(Array) && projects.empty? | |
66 # no results | |
67 return [[], 0] | |
68 end | |
69 | |
70 # TODO: make user an argument | |
71 user = User.current | |
72 tokens = [] << tokens unless tokens.is_a?(Array) | |
73 projects = [] << projects unless projects.nil? || projects.is_a?(Array) | |
74 | |
75 limit_options = {} | |
76 limit_options[:limit] = options[:limit] if options[:limit] | |
77 | |
78 columns = searchable_options[:columns] | |
79 columns = columns[0..0] if options[:titles_only] | |
80 | |
81 token_clauses = columns.collect {|column| "(LOWER(#{column}) LIKE ?)"} | |
82 | |
83 if !options[:titles_only] && searchable_options[:search_custom_fields] | |
84 searchable_custom_field_ids = CustomField.where(:type => "#{self.name}CustomField", :searchable => true).pluck(:id) | |
85 if searchable_custom_field_ids.any? | |
86 custom_field_sql = "#{table_name}.id IN (SELECT customized_id FROM #{CustomValue.table_name}" + | |
87 " WHERE customized_type='#{self.name}' AND customized_id=#{table_name}.id AND LOWER(value) LIKE ?" + | |
88 " AND #{CustomValue.table_name}.custom_field_id IN (#{searchable_custom_field_ids.join(',')}))" | |
89 token_clauses << custom_field_sql | |
90 end | |
91 end | |
92 | |
93 sql = (['(' + token_clauses.join(' OR ') + ')'] * tokens.size).join(options[:all_words] ? ' AND ' : ' OR ') | |
94 | |
95 tokens_conditions = [sql, * (tokens.collect {|w| "%#{w.downcase}%"} * token_clauses.size).sort] | |
96 | |
97 scope = self.scoped | |
98 project_conditions = [] | |
99 if searchable_options.has_key?(:permission) | |
100 project_conditions << Project.allowed_to_condition(user, searchable_options[:permission] || :view_project) | |
101 elsif respond_to?(:visible) | |
102 scope = scope.visible(user) | |
103 else | |
104 ActiveSupport::Deprecation.warn "acts_as_searchable with implicit :permission option is deprecated. Add a visible scope to the #{self.name} model or use explicit :permission option." | |
105 project_conditions << Project.allowed_to_condition(user, "view_#{self.name.underscore.pluralize}".to_sym) | |
106 end | |
107 # TODO: use visible scope options instead | |
108 project_conditions << "#{searchable_options[:project_key]} IN (#{projects.collect(&:id).join(',')})" unless projects.nil? | |
109 project_conditions = project_conditions.empty? ? nil : project_conditions.join(' AND ') | |
110 | |
111 results = [] | |
112 results_count = 0 | |
113 | |
114 scope = scope. | |
115 includes(searchable_options[:include]). | |
116 order("#{searchable_options[:order_column]} " + (options[:before] ? 'DESC' : 'ASC')). | |
117 where(project_conditions). | |
118 where(tokens_conditions) | |
119 | |
120 results_count = scope.count | |
121 | |
122 scope_with_limit = scope.limit(options[:limit]) | |
123 if options[:offset] | |
124 scope_with_limit = scope_with_limit.where("#{searchable_options[:date_column]} #{options[:before] ? '<' : '>'} ?", options[:offset]) | |
125 end | |
126 results = scope_with_limit.all | |
127 | |
128 [results, results_count] | |
129 end | |
130 end | |
131 end | |
132 end | |
133 end | |
134 end |