summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/models/custom_field.rb2
-rw-r--r--app/views/custom_fields/_form.rhtml17
-rw-r--r--db/migrate/086_add_custom_fields_searchable.rb9
-rw-r--r--lang/bg.yml1
-rw-r--r--lang/cs.yml1
-rw-r--r--lang/de.yml1
-rw-r--r--lang/en.yml1
-rw-r--r--lang/es.yml1
-rw-r--r--lang/fr.yml1
-rw-r--r--lang/he.yml1
-rw-r--r--lang/it.yml1
-rw-r--r--lang/ja.yml1
-rw-r--r--lang/ko.yml1
-rw-r--r--lang/nl.yml1
-rw-r--r--lang/pl.yml1
-rw-r--r--lang/pt-br.yml1
-rw-r--r--lang/pt.yml1
-rw-r--r--lang/ro.yml1
-rw-r--r--lang/ru.yml1
-rw-r--r--lang/sr.yml1
-rw-r--r--lang/sv.yml1
-rw-r--r--lang/zh-tw.yml1
-rw-r--r--lang/zh.yml1
-rw-r--r--test/fixtures/custom_fields.yml5
-rw-r--r--test/fixtures/custom_values.yml9
-rw-r--r--test/functional/search_controller_test.rb15
-rw-r--r--vendor/plugins/acts_as_searchable/lib/acts_as_searchable.rb23
27 files changed, 89 insertions, 11 deletions
diff --git a/app/models/custom_field.rb b/app/models/custom_field.rb
index c3b5f2a9f..e1fd8666d 100644
--- a/app/models/custom_field.rb
+++ b/app/models/custom_field.rb
@@ -43,6 +43,8 @@ class CustomField < ActiveRecord::Base
def before_validation
# remove empty values
self.possible_values = self.possible_values.collect{|v| v unless v.empty?}.compact
+ # make sure these fields are not searchable
+ self.searchable = false if %w(int float date bool).include?(field_format)
end
def validate
diff --git a/app/views/custom_fields/_form.rhtml b/app/views/custom_fields/_form.rhtml
index 013be9b70..915daab32 100644
--- a/app/views/custom_fields/_form.rhtml
+++ b/app/views/custom_fields/_form.rhtml
@@ -7,21 +7,32 @@ function toggle_custom_field_format() {
p_length = $("custom_field_min_length");
p_regexp = $("custom_field_regexp");
p_values = $("custom_field_possible_values");
+ p_searchable = $("custom_field_searchable");
switch (format.value) {
case "list":
Element.hide(p_length.parentNode);
Element.hide(p_regexp.parentNode);
+ Element.show(p_searchable.parentNode);
Element.show(p_values);
break;
case "date":
case "bool":
Element.hide(p_length.parentNode);
Element.hide(p_regexp.parentNode);
+ Element.hide(p_searchable.parentNode);
+ Element.hide(p_values);
+ break;
+ case "float":
+ case "int":
+ Element.show(p_length.parentNode);
+ Element.show(p_regexp.parentNode);
+ Element.hide(p_searchable.parentNode);
Element.hide(p_values);
break;
default:
Element.show(p_length.parentNode);
Element.show(p_regexp.parentNode);
+ Element.show(p_searchable.parentNode);
Element.hide(p_values);
break;
}
@@ -47,7 +58,6 @@ function deleteValueField(e) {
//]]>
</script>
-<!--[form:custom_field]-->
<div class="box">
<p><%= f.text_field :name, :required => true %></p>
<p><%= f.select :field_format, custom_field_formats_for_select, {}, :onchange => "toggle_custom_field_format();" %></p>
@@ -59,11 +69,8 @@ function deleteValueField(e) {
<% (@custom_field.possible_values.to_a + [""]).each do |value| %>
<span><%= text_field_tag 'custom_field[possible_values][]', value, :size => 30 %> <%= image_to_function "delete.png", "deleteValueField(this);return false" %><br /></span>
<% end %>
-
</p>
</div>
-<%= javascript_tag "toggle_custom_field_format();" %>
-<!--[eoform:custom_field]-->
<div class="box">
<% case @custom_field.type.to_s
@@ -78,6 +85,7 @@ when "IssueCustomField" %>
<p><%= f.check_box :is_required %></p>
<p><%= f.check_box :is_for_all %></p>
<p><%= f.check_box :is_filter %></p>
+ <p><%= f.check_box :searchable %></p>
<% when "UserCustomField" %>
<p><%= f.check_box :is_required %></p>
@@ -87,3 +95,4 @@ when "IssueCustomField" %>
<% end %>
</div>
+<%= javascript_tag "toggle_custom_field_format();" %>
diff --git a/db/migrate/086_add_custom_fields_searchable.rb b/db/migrate/086_add_custom_fields_searchable.rb
new file mode 100644
index 000000000..53158d14e
--- /dev/null
+++ b/db/migrate/086_add_custom_fields_searchable.rb
@@ -0,0 +1,9 @@
+class AddCustomFieldsSearchable < ActiveRecord::Migration
+ def self.up
+ add_column :custom_fields, :searchable, :boolean, :default => false
+ end
+
+ def self.down
+ remove_column :custom_fields, :searchable
+ end
+end
diff --git a/lang/bg.yml b/lang/bg.yml
index 590952681..d9bcd6c7c 100644
--- a/lang/bg.yml
+++ b/lang/bg.yml
@@ -549,3 +549,4 @@ text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
label_issues_by: Issues by %s
+field_searchable: Searchable
diff --git a/lang/cs.yml b/lang/cs.yml
index 816f9b92e..fe29defe6 100644
--- a/lang/cs.yml
+++ b/lang/cs.yml
@@ -549,3 +549,4 @@ text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
label_issues_by: Issues by %s
+field_searchable: Searchable
diff --git a/lang/de.yml b/lang/de.yml
index 046ed9994..c9cdc0c12 100644
--- a/lang/de.yml
+++ b/lang/de.yml
@@ -549,3 +549,4 @@ text_caracters_minimum: Muss mindestens %d Zeichen lang sein.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
label_issues_by: Issues by %s
+field_searchable: Searchable
diff --git a/lang/en.yml b/lang/en.yml
index 104e7fe6e..116935f73 100644
--- a/lang/en.yml
+++ b/lang/en.yml
@@ -170,6 +170,7 @@ field_redirect_existing_links: Redirect existing links
field_estimated_hours: Estimated time
field_column_names: Columns
field_time_zone: Time zone
+field_searchable: Searchable
setting_app_title: Application title
setting_app_subtitle: Application subtitle
diff --git a/lang/es.yml b/lang/es.yml
index d806d066e..50c652f2c 100644
--- a/lang/es.yml
+++ b/lang/es.yml
@@ -552,3 +552,4 @@ setting_time_format: Formato de hora
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
label_issues_by: Issues by %s
+field_searchable: Searchable
diff --git a/lang/fr.yml b/lang/fr.yml
index 36ccc463f..d6ad5da56 100644
--- a/lang/fr.yml
+++ b/lang/fr.yml
@@ -170,6 +170,7 @@ field_redirect_existing_links: Rediriger les liens existants
field_estimated_hours: Temps estimé
field_column_names: Colonnes
field_time_zone: Fuseau horaire
+field_searchable: Utilisé pour les recherches
setting_app_title: Titre de l'application
setting_app_subtitle: Sous-titre de l'application
diff --git a/lang/he.yml b/lang/he.yml
index 6be1a4c77..0ed57e527 100644
--- a/lang/he.yml
+++ b/lang/he.yml
@@ -549,3 +549,4 @@ text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
label_issues_by: Issues by %s
+field_searchable: Searchable
diff --git a/lang/it.yml b/lang/it.yml
index 8a3e954f4..d266f797e 100644
--- a/lang/it.yml
+++ b/lang/it.yml
@@ -549,3 +549,4 @@ text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
label_issues_by: Issues by %s
+field_searchable: Searchable
diff --git a/lang/ja.yml b/lang/ja.yml
index 1ecfb1ae9..bfe120cfe 100644
--- a/lang/ja.yml
+++ b/lang/ja.yml
@@ -550,3 +550,4 @@ text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
label_issues_by: Issues by %s
+field_searchable: Searchable
diff --git a/lang/ko.yml b/lang/ko.yml
index ef081e622..76debf345 100644
--- a/lang/ko.yml
+++ b/lang/ko.yml
@@ -549,3 +549,4 @@ text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
label_issues_by: Issues by %s
+field_searchable: Searchable
diff --git a/lang/nl.yml b/lang/nl.yml
index 24a343eb3..a8b5cc64a 100644
--- a/lang/nl.yml
+++ b/lang/nl.yml
@@ -550,3 +550,4 @@ text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
label_issues_by: Issues by %s
+field_searchable: Searchable
diff --git a/lang/pl.yml b/lang/pl.yml
index 222c7ea9d..5fa50ec51 100644
--- a/lang/pl.yml
+++ b/lang/pl.yml
@@ -549,3 +549,4 @@ text_caracters_minimum: Musi być nie krótsze niż %d znaków.
setting_bcc_recipients: Odbiorcy kopii tajnej (kt/bcc)
button_annotate: Adnotuj
label_issues_by: Zagadnienia wprowadzone przez %s
+field_searchable: Searchable
diff --git a/lang/pt-br.yml b/lang/pt-br.yml
index 8c903edd4..ed31915dd 100644
--- a/lang/pt-br.yml
+++ b/lang/pt-br.yml
@@ -549,3 +549,4 @@ text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
label_issues_by: Issues by %s
+field_searchable: Searchable
diff --git a/lang/pt.yml b/lang/pt.yml
index 10de07b5f..72ba4d2b0 100644
--- a/lang/pt.yml
+++ b/lang/pt.yml
@@ -549,3 +549,4 @@ text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
label_issues_by: Issues by %s
+field_searchable: Searchable
diff --git a/lang/ro.yml b/lang/ro.yml
index f7d3acd56..6f1eb7810 100644
--- a/lang/ro.yml
+++ b/lang/ro.yml
@@ -549,3 +549,4 @@ text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
label_issues_by: Issues by %s
+field_searchable: Searchable
diff --git a/lang/ru.yml b/lang/ru.yml
index cad357c0c..c7697ae1a 100644
--- a/lang/ru.yml
+++ b/lang/ru.yml
@@ -549,3 +549,4 @@ text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
label_issues_by: Issues by %s
+field_searchable: Searchable
diff --git a/lang/sr.yml b/lang/sr.yml
index f9008d890..b5e9ecfe3 100644
--- a/lang/sr.yml
+++ b/lang/sr.yml
@@ -550,3 +550,4 @@ text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
label_issues_by: Issues by %s
+field_searchable: Searchable
diff --git a/lang/sv.yml b/lang/sv.yml
index a4f55a17a..d789a2a37 100644
--- a/lang/sv.yml
+++ b/lang/sv.yml
@@ -550,3 +550,4 @@ text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
label_issues_by: Issues by %s
+field_searchable: Searchable
diff --git a/lang/zh-tw.yml b/lang/zh-tw.yml
index af0fd3ed4..4d730c1a9 100644
--- a/lang/zh-tw.yml
+++ b/lang/zh-tw.yml
@@ -549,3 +549,4 @@ default_activity_development: 開發
enumeration_issue_priorities: 項目重要性
enumeration_doc_categories: 文件分類
enumeration_activities: 活動 (time tracking)
+field_searchable: Searchable
diff --git a/lang/zh.yml b/lang/zh.yml
index de4ae1ece..6876daa17 100644
--- a/lang/zh.yml
+++ b/lang/zh.yml
@@ -552,3 +552,4 @@ text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
label_issues_by: Issues by %s
+field_searchable: Searchable
diff --git a/test/fixtures/custom_fields.yml b/test/fixtures/custom_fields.yml
index ce7509fe9..e73e6de96 100644
--- a/test/fixtures/custom_fields.yml
+++ b/test/fixtures/custom_fields.yml
@@ -11,16 +11,17 @@ custom_fields_001:
is_required: false
field_format: list
custom_fields_002:
- name: Build
+ name: Searchable field
min_length: 1
regexp: ""
is_for_all: true
type: IssueCustomField
- max_length: 10
+ max_length: 100
possible_values: ""
id: 2
is_required: false
field_format: string
+ searchable: true
custom_fields_003:
name: Development status
min_length: 0
diff --git a/test/fixtures/custom_values.yml b/test/fixtures/custom_values.yml
index b71227971..572142889 100644
--- a/test/fixtures/custom_values.yml
+++ b/test/fixtures/custom_values.yml
@@ -46,4 +46,11 @@ custom_values_008:
custom_field_id: 1
customized_id: 3
id: 11
- value: "MySQL" \ No newline at end of file
+ value: "MySQL"
+custom_values_009:
+ customized_type: Issue
+ custom_field_id: 2
+ customized_id: 3
+ id: 12
+ value: "this is a stringforcustomfield search"
+ \ No newline at end of file
diff --git a/test/functional/search_controller_test.rb b/test/functional/search_controller_test.rb
index 5e3673a4e..330cd0de0 100644
--- a/test/functional/search_controller_test.rb
+++ b/test/functional/search_controller_test.rb
@@ -5,7 +5,7 @@ require 'search_controller'
class SearchController; def rescue_action(e) raise e end; end
class SearchControllerTest < Test::Unit::TestCase
- fixtures :projects, :issues
+ fixtures :projects, :issues, :custom_fields, :custom_values
def setup
@controller = SearchController.new
@@ -25,7 +25,9 @@ class SearchControllerTest < Test::Unit::TestCase
assert assigns(:results).include?(Project.find(1))
end
- def test_search_in_project
+ def test_search_without_searchable_custom_fields
+ CustomField.update_all "searchable = #{ActiveRecord::Base.connection.quoted_false}"
+
get :index, :id => 1
assert_response :success
assert_template 'index'
@@ -36,6 +38,15 @@ class SearchControllerTest < Test::Unit::TestCase
assert_template 'index'
end
+ def test_search_with_searchable_custom_fields
+ get :index, :id => 1, :q => "stringforcustomfield"
+ assert_response :success
+ results = assigns(:results)
+ assert_not_nil results
+ assert_equal 1, results.size
+ assert results.include?(Issue.find(3))
+ end
+
def test_quick_jump_to_issue
# issue of a public project
get :index, :q => "3"
diff --git a/vendor/plugins/acts_as_searchable/lib/acts_as_searchable.rb b/vendor/plugins/acts_as_searchable/lib/acts_as_searchable.rb
index e2a323abb..1dd88978c 100644
--- a/vendor/plugins/acts_as_searchable/lib/acts_as_searchable.rb
+++ b/vendor/plugins/acts_as_searchable/lib/acts_as_searchable.rb
@@ -49,6 +49,9 @@ module Redmine
raise 'No date column defined defined.'
end
+ # Should we search custom fields on this model ?
+ searchable_options[:search_custom_fields] = !reflect_on_association(:custom_values).nil?
+
send :include, Redmine::Acts::Searchable::InstanceMethods
end
end
@@ -67,11 +70,27 @@ module Redmine
columns = searchable_options[:columns]
columns.slice!(1..-1) if options[:titles_only]
- sql = ([ '(' + columns.collect {|column| "(LOWER(#{column}) LIKE ?)"}.join(' OR ') + ')' ] * tokens.size).join(options[:all_words] ? ' AND ' : ' OR ')
+ token_clauses = columns.collect {|column| "(LOWER(#{column}) LIKE ?)"}
+
+ if !options[:titles_only] && searchable_options[:search_custom_fields]
+ searchable_custom_field_ids = CustomField.find(:all,
+ :select => 'id',
+ :conditions => { :type => "#{self.name}CustomField",
+ :searchable => true }).collect(&:id)
+ if searchable_custom_field_ids.any?
+ custom_field_sql = "#{table_name}.id IN (SELECT customized_id FROM #{CustomValue.table_name}" +
+ " WHERE customized_type='#{self.name}' AND customized_id=#{table_name}.id AND LOWER(value) LIKE ?" +
+ " AND #{CustomValue.table_name}.custom_field_id IN (#{searchable_custom_field_ids.join(',')}))"
+ token_clauses << custom_field_sql
+ end
+ end
+
+ sql = ([token_clauses.join(' OR ')] * tokens.size).join(options[:all_words] ? ' AND ' : ' OR ')
+
if options[:offset]
sql = "(#{sql}) AND (#{searchable_options[:date_column]} " + (options[:before] ? '<' : '>') + "'#{connection.quoted_date(options[:offset])}')"
end
- find_options[:conditions] = [sql, * (tokens * columns.size).sort]
+ find_options[:conditions] = [sql, * (tokens * token_clauses.size).sort]
results = with_scope(:find => {:conditions => ["#{searchable_options[:project_key]} = ?", project.id]}) do
find(:all, find_options)