Undev/redmine_xapian

View on GitHub
lib/redmine_xapian/search_controller_patch.rb

Summary

Maintainability
C
1 day
Test Coverage
require_dependency 'search_controller'
require 'will_paginate/array'

module RedmineXapian
  module SearchControllerPatch
    def self.included(base) # :nodoc:
      base.send(:include, InstanceMethods)

      base.class_eval do
        alias_method_chain :index, :xapian
        #def get_user_xapian_settings
        #  [@user_stem_lang, @user_stem_strategy]
        #end

        helper ::RedmineXapian::SearchHelper
      end
    end

    module InstanceMethods
      def index_with_xapian
        @question = params[:q] || ""
        @question.strip!
        @all_words = params[:all_words] ? params[:all_words].present? : true
        @titles_only = params[:titles_only] ? params[:titles_only].present? : false

        @user_stem_lang=params[:user_stem_lang] ? params[:user_stem_lang] : Setting.plugin_redmine_xapian['stemming_lang']
        @user_stem_strategy=params[:user_stem_strategy] ? params[:user_stem_strategy] : Setting.plugin_redmine_xapian['stemming_strategy']
        Rails.logger.debug "DEBUG: params[:user_stem_lang]" + params[:user_stem_lang].inspect + @user_stem_lang.inspect
        Rails.logger.debug "DEBUG: params[:user_stem_strategy]" + params[:user_stem_strategy].inspect + @user_stem_strategy.inspect

        projects_to_search = case params[:scope]
          when 'all'
            nil
          when 'my_projects'
            User.current.memberships.collect(&:project)
          when 'subprojects'
            @project ? (@project.self_and_descendants.active.all) : nil
          else
            @project
        end

        offset = nil
        begin; offset = params[:offset].to_time if params[:offset]; rescue; end

        # quick jump to an issue
        if @question.match(/^#?(\d+)$/) && Issue.visible.find_by_id($1.to_i)
          redirect_to :controller => "issues", :action => "show", :id => $1
          return
        end

        @object_types = Redmine::Search.available_search_types.dup
        if projects_to_search.is_a? Project
          # don't search projects
          @object_types.delete('projects')
          # only show what the user is allowed to view
          @object_types = @object_types.select do |o|
            if o == "attachments" || o == "repofiles"
              true
            else
              User.current.allowed_to?("view_#{o}".to_sym, projects_to_search)
            end
          end
        end

        @scope = @object_types.select {|t| params[t]}
        @scope = @object_types if @scope.empty?

        # extract tokens from the question
        # eg. hello "bye bye" => ["hello", "bye bye"]
        @tokens = @question.scan(%r{((\s|^)"[\s\w]+"(\s|$)|\S+)}).collect {|m| m.first.gsub(%r{(^\s*"\s*|\s*"\s*$)}, '')}
        # tokens must be at least 2 characters long
        @tokens = @tokens.uniq.select {|w| w.length > 1 }

        if @tokens.any?
          # no more than 5 tokens to search for
          @tokens.slice! 5..-1 if @tokens.size > 5

          @results = []
          @rresults = []
          @results_by_type = Hash.new {|h,k| h[k] = 0}

          limit = 10
          Rails.logger.debug "DEBUG: scope " + @scope.inspect
          @scope.each do |s|
            begin
              Rails.logger.debug "DEBUG: element: " + s.inspect
              r, c = s.singularize.camelcase.constantize.search(@tokens, projects_to_search,
              :all_words => @all_words,
              :titles_only => @titles_only,
              :limit => (limit+1),
              :offset => offset,
              :before => params[:previous].nil?,
              :user_stem_lang => @user_stem_lang,
              :user_stem_strategy => @user_stem_strategy)
                  @rresults += r
                  @results_by_type[s] += c
            rescue => error
              flash[:error] = "#{error}: searching model #{s.inspect}"
            end
          end
          @results = @rresults.sort {|a,b| b.event_datetime <=> a.event_datetime}

          if params[:previous].nil?
            @pagination_previous_date = @results[0].event_datetime if offset && @results[0]
            if @results.size > limit
              @pagination_next_date = @results[limit-1].event_datetime
              @results = @results[0, limit]
            end
          else
            @pagination_next_date = @results[-1].event_datetime if offset && @results[-1]
            if @results.size > limit
              @pagination_previous_date = @results[-(limit)].event_datetime
              @results = @results[-(limit), limit]
            end
          end

        else
          @question = ""
          flash.delete(:error)
        end
        render :layout => false if request.xhr?
      end

      def get_user_xapian_settings
        [@user_stem_lang, @user_stem_strategy]
      end
    end
  end
end