To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
root / vendor / plugins / acts_as_searchable / lib / .svn / text-base / acts_as_searchable.rb.svn-base @ 442:753f1380d6bc
History | View | Annotate | Download (6.21 KB)
| 1 | 441:cbce1fd3b1b7 | Chris | # Redmine - project management software |
|---|---|---|---|
| 2 | # Copyright (C) 2006-2011 Jean-Philippe Lang |
||
| 3 | 0:513646585e45 | Chris | # |
| 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 | 441:cbce1fd3b1b7 | Chris | # TODO: make user an argument |
| 66 | user = User.current |
||
| 67 | 0:513646585e45 | Chris | tokens = [] << tokens unless tokens.is_a?(Array) |
| 68 | projects = [] << projects unless projects.nil? || projects.is_a?(Array) |
||
| 69 | |||
| 70 | find_options = {:include => searchable_options[:include]}
|
||
| 71 | find_options[:order] = "#{searchable_options[:order_column]} " + (options[:before] ? 'DESC' : 'ASC')
|
||
| 72 | |||
| 73 | limit_options = {}
|
||
| 74 | limit_options[:limit] = options[:limit] if options[:limit] |
||
| 75 | if options[:offset] |
||
| 76 | limit_options[:conditions] = "(#{searchable_options[:date_column]} " + (options[:before] ? '<' : '>') + "'#{connection.quoted_date(options[:offset])}')"
|
||
| 77 | end |
||
| 78 | |||
| 79 | columns = searchable_options[:columns] |
||
| 80 | columns = columns[0..0] if options[:titles_only] |
||
| 81 | |||
| 82 | token_clauses = columns.collect {|column| "(LOWER(#{column}) LIKE ?)"}
|
||
| 83 | |||
| 84 | if !options[:titles_only] && searchable_options[:search_custom_fields] |
||
| 85 | searchable_custom_field_ids = CustomField.find(:all, |
||
| 86 | :select => 'id', |
||
| 87 | :conditions => { :type => "#{self.name}CustomField",
|
||
| 88 | :searchable => true }).collect(&:id) |
||
| 89 | if searchable_custom_field_ids.any? |
||
| 90 | custom_field_sql = "#{table_name}.id IN (SELECT customized_id FROM #{CustomValue.table_name}" +
|
||
| 91 | " WHERE customized_type='#{self.name}' AND customized_id=#{table_name}.id AND LOWER(value) LIKE ?" +
|
||
| 92 | " AND #{CustomValue.table_name}.custom_field_id IN (#{searchable_custom_field_ids.join(',')}))"
|
||
| 93 | token_clauses << custom_field_sql |
||
| 94 | end |
||
| 95 | end |
||
| 96 | |||
| 97 | sql = (['(' + token_clauses.join(' OR ') + ')'] * tokens.size).join(options[:all_words] ? ' AND ' : ' OR ')
|
||
| 98 | |||
| 99 | find_options[:conditions] = [sql, * (tokens.collect {|w| "%#{w.downcase}%"} * token_clauses.size).sort]
|
||
| 100 | |||
| 101 | 441:cbce1fd3b1b7 | Chris | scope = self |
| 102 | 0:513646585e45 | Chris | project_conditions = [] |
| 103 | 441:cbce1fd3b1b7 | Chris | if searchable_options.has_key?(:permission) |
| 104 | project_conditions << Project.allowed_to_condition(user, searchable_options[:permission] || :view_project) |
||
| 105 | elsif respond_to?(:visible) |
||
| 106 | scope = scope.visible(user) |
||
| 107 | else |
||
| 108 | 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."
|
||
| 109 | project_conditions << Project.allowed_to_condition(user, "view_#{self.name.underscore.pluralize}".to_sym)
|
||
| 110 | end |
||
| 111 | # TODO: use visible scope options instead |
||
| 112 | 0:513646585e45 | Chris | project_conditions << "#{searchable_options[:project_key]} IN (#{projects.collect(&:id).join(',')})" unless projects.nil?
|
| 113 | 441:cbce1fd3b1b7 | Chris | project_conditions = project_conditions.empty? ? nil : project_conditions.join(' AND ')
|
| 114 | 0:513646585e45 | Chris | |
| 115 | results = [] |
||
| 116 | results_count = 0 |
||
| 117 | |||
| 118 | 441:cbce1fd3b1b7 | Chris | with_scope(:find => {:conditions => project_conditions}) do
|
| 119 | 0:513646585e45 | Chris | with_scope(:find => find_options) do |
| 120 | 441:cbce1fd3b1b7 | Chris | results_count = scope.count(:all) |
| 121 | results = scope.find(:all, limit_options) |
||
| 122 | 0:513646585e45 | Chris | end |
| 123 | end |
||
| 124 | [results, results_count] |
||
| 125 | end |
||
| 126 | end |
||
| 127 | end |
||
| 128 | end |
||
| 129 | end |
||
| 130 | end |