Mercurial > hg > soundsoftware-site
comparison .svn/pristine/73/736047ee9f35586c5d4e470ce8c96567b46d2959.svn-base @ 1517:dffacf8a6908 redmine-2.5
Update to Redmine SVN revision 13367 on 2.5-stable branch
author | Chris Cannam |
---|---|
date | Tue, 09 Sep 2014 09:29:00 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
1516:b450a9d58aed | 1517:dffacf8a6908 |
---|---|
1 # Redmine - project management software | |
2 # Copyright (C) 2006-2014 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_fields = CustomField.where(:type => "#{self.name}CustomField", :searchable => true) | |
85 fields_by_visibility = searchable_custom_fields.group_by {|field| | |
86 field.visibility_by_project_condition(searchable_options[:project_key], user, "cfs.custom_field_id") | |
87 } | |
88 # only 1 subquery for all custom fields with the same visibility statement | |
89 fields_by_visibility.each do |visibility, fields| | |
90 ids = fields.map(&:id).join(',') | |
91 sql = "#{table_name}.id IN (SELECT cfs.customized_id FROM #{CustomValue.table_name} cfs" + | |
92 " WHERE cfs.customized_type='#{self.name}' AND cfs.customized_id=#{table_name}.id AND LOWER(cfs.value) LIKE ?" + | |
93 " AND cfs.custom_field_id IN (#{ids})" + | |
94 " AND #{visibility})" | |
95 token_clauses << sql | |
96 end | |
97 end | |
98 | |
99 sql = (['(' + token_clauses.join(' OR ') + ')'] * tokens.size).join(options[:all_words] ? ' AND ' : ' OR ') | |
100 | |
101 tokens_conditions = [sql, * (tokens.collect {|w| "%#{w.downcase}%"} * token_clauses.size).sort] | |
102 | |
103 scope = self.scoped | |
104 project_conditions = [] | |
105 if searchable_options.has_key?(:permission) | |
106 project_conditions << Project.allowed_to_condition(user, searchable_options[:permission] || :view_project) | |
107 elsif respond_to?(:visible) | |
108 scope = scope.visible(user) | |
109 else | |
110 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." | |
111 project_conditions << Project.allowed_to_condition(user, "view_#{self.name.underscore.pluralize}".to_sym) | |
112 end | |
113 # TODO: use visible scope options instead | |
114 project_conditions << "#{searchable_options[:project_key]} IN (#{projects.collect(&:id).join(',')})" unless projects.nil? | |
115 project_conditions = project_conditions.empty? ? nil : project_conditions.join(' AND ') | |
116 | |
117 results = [] | |
118 results_count = 0 | |
119 | |
120 scope = scope. | |
121 includes(searchable_options[:include]). | |
122 order("#{searchable_options[:order_column]} " + (options[:before] ? 'DESC' : 'ASC')). | |
123 where(project_conditions). | |
124 where(tokens_conditions) | |
125 | |
126 results_count = scope.count | |
127 | |
128 scope_with_limit = scope.limit(options[:limit]) | |
129 if options[:offset] | |
130 scope_with_limit = scope_with_limit.where("#{searchable_options[:date_column]} #{options[:before] ? '<' : '>'} ?", options[:offset]) | |
131 end | |
132 results = scope_with_limit.all | |
133 | |
134 [results, results_count] | |
135 end | |
136 end | |
137 end | |
138 end | |
139 end | |
140 end |