@@ -24,6 +24,7 class SearchController < ApplicationController | |||||
24 | @all_words = params[:all_words] ? params[:all_words].present? : true |
|
24 | @all_words = params[:all_words] ? params[:all_words].present? : true | |
25 | @titles_only = params[:titles_only] ? params[:titles_only].present? : false |
|
25 | @titles_only = params[:titles_only] ? params[:titles_only].present? : false | |
26 | @search_attachments = params[:attachments].presence || '0' |
|
26 | @search_attachments = params[:attachments].presence || '0' | |
|
27 | @open_issues = params[:open_issues] ? params[:open_issues].present? : false | |||
27 |
|
28 | |||
28 | # quick jump to an issue |
|
29 | # quick jump to an issue | |
29 | if (m = @question.match(/^#?(\d+)$/)) && (issue = Issue.visible.find_by_id(m[1].to_i)) |
|
30 | if (m = @question.match(/^#?(\d+)$/)) && (issue = Issue.visible.find_by_id(m[1].to_i)) | |
@@ -56,7 +57,7 class SearchController < ApplicationController | |||||
56 |
|
57 | |||
57 | fetcher = Redmine::Search::Fetcher.new( |
|
58 | fetcher = Redmine::Search::Fetcher.new( | |
58 | @question, User.current, @scope, projects_to_search, |
|
59 | @question, User.current, @scope, projects_to_search, | |
59 | :all_words => @all_words, :titles_only => @titles_only, :attachments => @search_attachments, |
|
60 | :all_words => @all_words, :titles_only => @titles_only, :attachments => @search_attachments, :open_issues => @open_issues, | |
60 | :cache => params[:page].present? |
|
61 | :cache => params[:page].present? | |
61 | ) |
|
62 | ) | |
62 |
|
63 |
@@ -47,7 +47,8 class Issue < ActiveRecord::Base | |||||
47 | acts_as_customizable |
|
47 | acts_as_customizable | |
48 | acts_as_watchable |
|
48 | acts_as_watchable | |
49 | acts_as_searchable :columns => ['subject', "#{table_name}.description"], |
|
49 | acts_as_searchable :columns => ['subject', "#{table_name}.description"], | |
50 | :preload => [:project, :status, :tracker] |
|
50 | :preload => [:project, :status, :tracker], | |
|
51 | :scope => lambda {|options| options[:open_issues] ? self.open : self.all} | |||
51 |
|
52 | |||
52 | acts_as_event :title => Proc.new {|o| "#{o.tracker.name} ##{o.id} (#{o.status}): #{o.subject}"}, |
|
53 | acts_as_event :title => Proc.new {|o| "#{o.tracker.name} ##{o.id} (#{o.status}): #{o.subject}"}, | |
53 | :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.id}}, |
|
54 | :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.id}}, |
@@ -20,6 +20,7 | |||||
20 | <fieldset class="collapsible collapsed"> |
|
20 | <fieldset class="collapsible collapsed"> | |
21 | <legend onclick="toggleFieldset(this);"><%= l(:label_options) %></legend> |
|
21 | <legend onclick="toggleFieldset(this);"><%= l(:label_options) %></legend> | |
22 | <div id="options-content" style="display:none;"> |
|
22 | <div id="options-content" style="display:none;"> | |
|
23 | <p><label><%= check_box_tag 'open_issues', 1, @open_issues %> <%= l(:label_search_open_issues_only) %></label></p> | |||
23 | <p> |
|
24 | <p> | |
24 | <label><%= radio_button_tag 'attachments', '0', @search_attachments == '0' %> <%= l(:label_search_attachments_no) %></label> |
|
25 | <label><%= radio_button_tag 'attachments', '0', @search_attachments == '0' %> <%= l(:label_search_attachments_no) %></label> | |
25 | <label><%= radio_button_tag 'attachments', '1', @search_attachments == '1' %> <%= l(:label_search_attachments_yes) %></label> |
|
26 | <label><%= radio_button_tag 'attachments', '1', @search_attachments == '1' %> <%= l(:label_search_attachments_yes) %></label> |
@@ -930,6 +930,7 en: | |||||
930 | label_search_attachments_yes: Search attachment filenames and descriptions |
|
930 | label_search_attachments_yes: Search attachment filenames and descriptions | |
931 | label_search_attachments_no: Do not search attachments |
|
931 | label_search_attachments_no: Do not search attachments | |
932 | label_search_attachments_only: Search attachments only |
|
932 | label_search_attachments_only: Search attachments only | |
|
933 | label_search_open_issues_only: Open issues only | |||
933 |
|
934 | |||
934 | button_login: Login |
|
935 | button_login: Login | |
935 | button_submit: Submit |
|
936 | button_submit: Submit |
@@ -950,6 +950,7 fr: | |||||
950 | label_search_attachments_yes: Rechercher les noms et descriptions de fichiers |
|
950 | label_search_attachments_yes: Rechercher les noms et descriptions de fichiers | |
951 | label_search_attachments_no: Ne pas rechercher les fichiers |
|
951 | label_search_attachments_no: Ne pas rechercher les fichiers | |
952 | label_search_attachments_only: Rechercher les fichiers uniquement |
|
952 | label_search_attachments_only: Rechercher les fichiers uniquement | |
|
953 | label_search_open_issues_only: Demandes ouvertes uniquement | |||
953 |
|
954 | |||
954 | button_login: Connexion |
|
955 | button_login: Connexion | |
955 | button_submit: Soumettre |
|
956 | button_submit: Soumettre |
@@ -89,7 +89,7 module Redmine | |||||
89 |
|
89 | |||
90 | unless options[:attachments] == 'only' |
|
90 | unless options[:attachments] == 'only' | |
91 | r = fetch_ranks_and_ids( |
|
91 | r = fetch_ranks_and_ids( | |
92 | search_scope(user, projects). |
|
92 | search_scope(user, projects, options). | |
93 | where(search_tokens_condition(columns, tokens, options[:all_words])), |
|
93 | where(search_tokens_condition(columns, tokens, options[:all_words])), | |
94 | options[:limit] |
|
94 | options[:limit] | |
95 | ) |
|
95 | ) | |
@@ -109,7 +109,7 module Redmine | |||||
109 | visibility = clauses.join(' OR ') |
|
109 | visibility = clauses.join(' OR ') | |
110 |
|
110 | |||
111 | r |= fetch_ranks_and_ids( |
|
111 | r |= fetch_ranks_and_ids( | |
112 | search_scope(user, projects). |
|
112 | search_scope(user, projects, options). | |
113 | joins(:custom_values). |
|
113 | joins(:custom_values). | |
114 | where(visibility). |
|
114 | where(visibility). | |
115 | where(search_tokens_condition(["#{CustomValue.table_name}.value"], tokens, options[:all_words])), |
|
115 | where(search_tokens_condition(["#{CustomValue.table_name}.value"], tokens, options[:all_words])), | |
@@ -121,7 +121,7 module Redmine | |||||
121 |
|
121 | |||
122 | if !options[:titles_only] && searchable_options[:search_journals] |
|
122 | if !options[:titles_only] && searchable_options[:search_journals] | |
123 | r |= fetch_ranks_and_ids( |
|
123 | r |= fetch_ranks_and_ids( | |
124 | search_scope(user, projects). |
|
124 | search_scope(user, projects, options). | |
125 | joins(:journals). |
|
125 | joins(:journals). | |
126 | where("#{Journal.table_name}.private_notes = ? OR (#{Project.allowed_to_condition(user, :view_private_notes)})", false). |
|
126 | where("#{Journal.table_name}.private_notes = ? OR (#{Project.allowed_to_condition(user, :view_private_notes)})", false). | |
127 | where(search_tokens_condition(["#{Journal.table_name}.notes"], tokens, options[:all_words])), |
|
127 | where(search_tokens_condition(["#{Journal.table_name}.notes"], tokens, options[:all_words])), | |
@@ -133,7 +133,7 module Redmine | |||||
133 |
|
133 | |||
134 | if searchable_options[:search_attachments] && (options[:titles_only] ? options[:attachments] == 'only' : options[:attachments] != '0') |
|
134 | if searchable_options[:search_attachments] && (options[:titles_only] ? options[:attachments] == 'only' : options[:attachments] != '0') | |
135 | r |= fetch_ranks_and_ids( |
|
135 | r |= fetch_ranks_and_ids( | |
136 | search_scope(user, projects). |
|
136 | search_scope(user, projects, options). | |
137 | joins(:attachments). |
|
137 | joins(:attachments). | |
138 | where(search_tokens_condition(["#{Attachment.table_name}.filename", "#{Attachment.table_name}.description"], tokens, options[:all_words])), |
|
138 | where(search_tokens_condition(["#{Attachment.table_name}.filename", "#{Attachment.table_name}.description"], tokens, options[:all_words])), | |
139 | options[:limit] |
|
139 | options[:limit] | |
@@ -180,7 +180,7 module Redmine | |||||
180 | private :fetch_ranks_and_ids |
|
180 | private :fetch_ranks_and_ids | |
181 |
|
181 | |||
182 | # Returns the search scope for user and projects |
|
182 | # Returns the search scope for user and projects | |
183 | def search_scope(user, projects) |
|
183 | def search_scope(user, projects, options={}) | |
184 | if projects.is_a?(Array) && projects.empty? |
|
184 | if projects.is_a?(Array) && projects.empty? | |
185 | # no results |
|
185 | # no results | |
186 | return none |
|
186 | return none | |
@@ -188,7 +188,7 module Redmine | |||||
188 |
|
188 | |||
189 | scope = (searchable_options[:scope] || self) |
|
189 | scope = (searchable_options[:scope] || self) | |
190 | if scope.is_a? Proc |
|
190 | if scope.is_a? Proc | |
191 | scope = scope.call |
|
191 | scope = scope.call(options) | |
192 | end |
|
192 | end | |
193 |
|
193 | |||
194 | if respond_to?(:visible) && !searchable_options.has_key?(:permission) |
|
194 | if respond_to?(:visible) && !searchable_options.has_key?(:permission) |
@@ -209,6 +209,15 class SearchControllerTest < ActionController::TestCase | |||||
209 | assert_equal 2, results.size |
|
209 | assert_equal 2, results.size | |
210 | end |
|
210 | end | |
211 |
|
211 | |||
|
212 | def test_search_open_issues | |||
|
213 | Issue.generate! :subject => 'search_open' | |||
|
214 | Issue.generate! :subject => 'search_open', :status_id => 5 | |||
|
215 | ||||
|
216 | get :index, :id => 1, :q => 'search_open', :open_issues => '1' | |||
|
217 | results = assigns(:results) | |||
|
218 | assert_equal 1, results.size | |||
|
219 | end | |||
|
220 | ||||
212 | def test_search_all_words |
|
221 | def test_search_all_words | |
213 | # 'all words' is on by default |
|
222 | # 'all words' is on by default | |
214 | get :index, :id => 1, :q => 'recipe updating saving', :all_words => '1' |
|
223 | get :index, :id => 1, :q => 'recipe updating saving', :all_words => '1' |
General Comments 0
You need to be logged in to leave comments.
Login now