Noosfero/noosfero

View on GitHub
plugins/elasticsearch/helpers/elasticsearch_helper.rb

Summary

Maintainability
A
0 mins
Test Coverage
module ElasticsearchHelper
  def searchable_types
    {
      all: _("All results"),
      text_article: _("Articles"),
      uploaded_file: _("Files"),
      community: _("Communities"),
      event: _("Events"),
      person: _("People")
    }
  end

  def sort_types
    sorts = {
      relevance: _("Relevance"),
      lexical: _("Alphabetical"),
      more_recent: _("More recent")
    }

    selected_type = (params[:selected_type] || nil)

    if selected_type && (selected_type.to_sym != :all)
      klass = selected_type.to_s.classify.constantize
      sorts.update klass.specific_sort if klass.respond_to? :specific_sort
    end
    sorts
  end

  def process_results
    selected_type = (params[:selected_type].presence || :all).to_sym
    selected_type == :all ? search_from_all_models : search_from_model(selected_type)
  end

  private

    def search_from_all_models
      begin
        filter = (params[:filter] || "").to_sym
        query = get_query params[:query], sort_by: get_sort_by(filter), categories: params[:categories]
        Elasticsearch::Model.search(query, searchable_models, size: default_per_page(params[:per_page])).page(params[:page]).records
      rescue
        []
      end
    end

    def search_from_model(model)
      begin
        klass = model.to_s.classify.constantize
        filter = (params[:filter] || "").to_sym
        query = get_query params[:query], klass: klass, sort_by: get_sort_by(filter, klass), categories: params[:categories]
        klass.search(query, size: default_per_page(params[:per_page])).page(params[:page]).records
      rescue
        []
      end
    end

    def default_per_page(per_page = nil)
      per_page || 10
    end

    def get_sort_by(sort_by, klass = nil)
      case sort_by
      when :lexical
        { "name.raw" => { "order" => "asc" } }
      when :more_recent
        { "created_at" => { "order" => "desc" } }
      else
        (klass && klass.respond_to?(:get_sort_by)) ? klass.get_sort_by(sort_by) : nil
      end
    end

    def searchable_models
      searchable_types.except(:all).keys.map { |model| model.to_s.classify.constantize }
    end

    def query_string(expression = "", models = [])
      return { match_all: {} } if not expression

      {
        query_string: {
          query: "*" + expression.downcase.split.join("* *") + "*",
          fields: fields_from_models(models),
          tie_breaker: 0.4,
          minimum_should_match: "100%"
        }
      }
    end

    def query_method(expression = "", models = [], categories = [])
      query = {}
      current_user ||= nil

      query[:query] = {
        filtered: {
          query: query_string(expression, models),
          filter: {
            bool: {}
          }
        }
      }

      query[:query][:filtered][:filter][:bool] = {
        should: models.map { |model| model.filter(environment: @environment.id, user: current_user) }
      }

      unless categories.blank?
        query[:query][:filtered][:filter][:bool][:must] = models.first.filter_category(categories)
      end

      query
    end

    def get_query(text = "", options = {})
      klass = options[:klass]
      sort_by = options[:sort_by]
      categories = (options[:categories] || "").split(",")
      categories = categories.map(&:to_i)

      models = (klass.nil?) ? searchable_models : [klass]

      query = query_method(text, models, categories)
      query[:sort] = sort_by if sort_by

      query
    end

    def fields_from_models(klasses)
      fields = Set.new
      klasses.each do |klass|
        klass::SEARCHABLE_FIELDS.map do |key, value|
          if value && value[:weight]
            fields.add "#{key}^#{value[:weight]}"
          else
            fields.add "#{key}"
          end
        end
      end
      fields.to_a
    end
end