You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

search_controller.rb 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. # redMine - project management software
  2. # Copyright (C) 2006 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. class SearchController < ApplicationController
  18. layout 'base'
  19. before_filter :find_optional_project
  20. helper :messages
  21. include MessagesHelper
  22. def index
  23. @question = params[:q] || ""
  24. @question.strip!
  25. @all_words = params[:all_words] || (params[:submit] ? false : true)
  26. @titles_only = !params[:titles_only].nil?
  27. offset = nil
  28. begin; offset = params[:offset].to_time if params[:offset]; rescue; end
  29. # quick jump to an issue
  30. if @question.match(/^#?(\d+)$/) && Issue.find_by_id($1, :include => :project, :conditions => Project.visible_by(User.current))
  31. redirect_to :controller => "issues", :action => "show", :id => $1
  32. return
  33. end
  34. if @project
  35. # only show what the user is allowed to view
  36. @object_types = %w(issues news documents changesets wiki_pages messages)
  37. @object_types = @object_types.select {|o| User.current.allowed_to?("view_#{o}".to_sym, @project)}
  38. @scope = @object_types.select {|t| params[t]}
  39. @scope = @object_types if @scope.empty?
  40. else
  41. @object_types = @scope = %w(projects)
  42. end
  43. # extract tokens from the question
  44. # eg. hello "bye bye" => ["hello", "bye bye"]
  45. @tokens = @question.scan(%r{((\s|^)"[\s\w]+"(\s|$)|\S+)}).collect {|m| m.first.gsub(%r{(^\s*"\s*|\s*"\s*$)}, '')}
  46. # tokens must be at least 3 character long
  47. @tokens = @tokens.uniq.select {|w| w.length > 2 }
  48. if !@tokens.empty?
  49. # no more than 5 tokens to search for
  50. @tokens.slice! 5..-1 if @tokens.size > 5
  51. # strings used in sql like statement
  52. like_tokens = @tokens.collect {|w| "%#{w.downcase}%"}
  53. @results = []
  54. limit = 10
  55. if @project
  56. @scope.each do |s|
  57. @results += s.singularize.camelcase.constantize.search(like_tokens, @project,
  58. :all_words => @all_words,
  59. :titles_only => @titles_only,
  60. :limit => (limit+1),
  61. :offset => offset,
  62. :before => params[:previous].nil?)
  63. end
  64. @results = @results.sort {|a,b| b.event_datetime <=> a.event_datetime}
  65. if params[:previous].nil?
  66. @pagination_previous_date = @results[0].event_datetime if offset && @results[0]
  67. if @results.size > limit
  68. @pagination_next_date = @results[limit-1].event_datetime
  69. @results = @results[0, limit]
  70. end
  71. else
  72. @pagination_next_date = @results[-1].event_datetime if offset && @results[-1]
  73. if @results.size > limit
  74. @pagination_previous_date = @results[-(limit)].event_datetime
  75. @results = @results[-(limit), limit]
  76. end
  77. end
  78. else
  79. operator = @all_words ? ' AND ' : ' OR '
  80. @results += Project.find(:all,
  81. :limit => limit,
  82. :conditions => [ (["(#{Project.visible_by(User.current)}) AND (LOWER(name) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort]
  83. ) if @scope.include? 'projects'
  84. # if only one project is found, user is redirected to its overview
  85. redirect_to :controller => 'projects', :action => 'show', :id => @results.first and return if @results.size == 1
  86. end
  87. else
  88. @question = ""
  89. end
  90. render :layout => false if request.xhr?
  91. end
  92. private
  93. def find_optional_project
  94. return true unless params[:id]
  95. @project = Project.find(params[:id])
  96. check_project_privacy
  97. rescue ActiveRecord::RecordNotFound
  98. render_404
  99. end
  100. end