publiclab/plots2

View on GitHub
app/api/srch/search.rb

Summary

Maintainability
C
7 hrs
Test Coverage
require 'grape'
require 'grape-entity'

module Srch
  class Search < Grape::API
    include Skylight::Helpers

    # we are using a group of reusable parameters using a shared params helper
    # see /app/api/srch/shared_params.rb
    helpers SharedParams

    include Grape::Rails::Cache

    # Endpoint definitions
    # Basic implementation from classic plots2 SearchController
    resource :srch do
      # Request URL should be /api/srch/all?query=QRY
      desc 'Perform a search of all available resources', hidden: false,
                                                          is_array: false,
                                                          nickname: 'search_all'
      params do
        use :common
      end
      get :all do
        search_request = SearchRequest.from_request(params)
        results = Search.execute(:all, params)
        results_list = []

        if results.present?
          results_list << results[:profiles].map do |model|
            DocResult.new(
              doc_type: 'USERS',
              doc_url: "/profile/#{model.name}",
              doc_title: model.username
            )
          end

          results_list << results[:notes].map do |model|
            DocResult.new(
              doc_id: model.nid,
              doc_type: 'NOTES',
              doc_url: model.path,
              doc_title: model.title
            )
          end

          results_list << results[:wikis].map do |model|
            DocResult.new(
              doc_id: model.nid,
              doc_type: 'WIKIS',
              doc_url: model.path,
              doc_title: model.title
            )
          end

          results_list << results[:tags].map do |model|
            DocResult.new(
              doc_id: model.nid,
              doc_type: 'TAGS',
              doc_url: model.path,
              doc_title: model.title
            )
          end

          results_list << results[:maps].map do |model|
            DocResult.new(
              doc_id: model.nid,
              doc_type: 'PLACES',
              doc_url: model.path,
              doc_title: model.title
            )
          end

          results_list << results[:questions].map do |model|
            DocResult.new(
              doc_id: model.nid,
              doc_type: 'QUESTIONS',
              doc_url: model.path(:question),
              doc_title: model.title,
              score: model.comments.length
            )
          end
          DocList.new(results_list.flatten, search_request)
        else
          DocList.new('', search_request)
        end
      end

      # Request URL should be /api/srch/profiles?query=QRY[&sort_by=recent&order_direction=desc&field=username]
      desc 'Perform a search of profiles', hidden: false,
                                           is_array: false,
                                           nickname: 'search_profiles'

      params do
        use :common, :sorting, :ordering, :field
      end
      get :profiles do
        search_request = SearchRequest.from_request(params)
        # TODO: evaluate if disabling this caching action actually speeds things up?
        cache(key: "api:profiles:#{params[:query]}:#{params[:limit]}:#{params[:sort_by]}:#{params[:order_direction]}:#{params[:field]}", expires_in: 2.day) do
          results = Search.execute(:profiles, params)

          if results.present?
            docs = results.map do |model|
              DocResult.new(
                doc_type: 'USERS',
                doc_url: "/profile/#{model.name}",
                doc_title: model.username,
                latitude: model.lat,
                longitude: model.lon,
                blurred: model.blurred?
              )
            end
            DocList.new(docs, search_request)
          else
            DocList.new('', search_request)
          end
        end
      end

      # Request URL should be /api/srch/notes?query=QRY
      desc 'Perform a search of research notes', hidden: false,
                                                 is_array: false,
                                                 nickname: 'search_notes'

      params do
        use :common
      end
      get :notes do
        search_request = SearchRequest.from_request(params)
        results = Search.execute(:notes, params)

        if results.present?
          docs = results.map do |model|
            DocResult.new(
              doc_id: model.nid,
              doc_type: 'NOTES',
              doc_url: model.path,
              doc_title: model.title
            )
          end

          DocList.new(docs, search_request)
        else
          DocList.new('', search_request)
        end
      end

      # Request URL should be /api/srch/content?query=QRY
      desc 'Perform a search of nodes and tags', hidden: false,
                                                 is_array: false,
                                                 nickname: 'search_content'

      params do
        use :common
      end
      get :content do
        search_request = SearchRequest.from_request(params)
        results = Search.execute(:content, params)
        results_list = []

        if results.present?
          results_list << results[:tags].map do |tagname|
            DocResult.new(
              doc_id: tagname,
              doc_type: 'TAGS',
              doc_url: "/tag/#{tagname}",
              doc_title: tagname
            )
          end
          results_list << results[:notes].map do |model|
            DocResult.new(
              doc_id: model.nid,
              doc_type: 'NOTES',
              doc_url: model.path,
              doc_title: model.title
            )
          end
          DocList.new(results_list.flatten, search_request)
        else
          DocList.new('', search_request)
        end
      end

      # Request URL should be /api/srch/nodes?query=QRY
      desc 'Perform a search of nodes', hidden: false,
                                                 is_array: false,
                                                 nickname: 'search_content'

      params do
        use :common
      end
      get :nodes do
        search_request = SearchRequest.from_request(params)
        results = Search.execute(:nodes, params)

        if results.present?
          docs = results.map do |model|
            DocResult.new(
              doc_id: model.nid,
              doc_type: 'NODES',
              doc_url: model.path,
              doc_title: model.title
            )
          end

          DocList.new(docs, search_request)
        else
          DocList.new('', search_request)
        end
      end

      # Request URL should be /api/srch/wikis?query=QRY
      desc 'Perform a search of wikis pages',    hidden: false,
                                                 is_array: false,
                                                 nickname: 'search_wikis'

      params do
        use :common
      end
      get :wikis do
        search_request = SearchRequest.from_request(params)
        results = Search.execute(:wikis, params)

        if results.present?
          docs = results.map do |model|
            DocResult.new(
              doc_id: model.nid,
              doc_type: 'WIKIS',
              doc_url: model.path,
              doc_title: model.title
            )
          end

          DocList.new(docs, search_request)
        else
          DocList.new('', search_request)
        end
      end

      # Request URL should be /api/srch/questions?query=QRY
      desc 'Perform a search of questions tables', hidden: false,
                                                   is_array: false,
                                                   nickname: 'search_questions'

      params do
        use :common, :sorting, :ordering
      end
      get :questions do
        search_request = SearchRequest.from_request(params)
        results = Search.execute(:questions, params)

        if results.present?
          docs = results.map do |model|
            DocResult.new(
              doc_id: model.nid,
              doc_type: 'QUESTIONS',
              doc_url: model.path(:question),
              doc_title: model.title,
              score: model.comments.length
            )
          end

          DocList.new(docs, search_request)
        else
          DocList.new('', search_request)
        end
      end

      # Request URL should be /api/srch/tags?query=QRY
      desc 'Perform a search of documents associated with tags within the system', hidden: false,
                                                                                   is_array: false,
                                                                                   nickname: 'search_tags'

      params do
        use :common
      end
      get :tags do
        Skylight.instrument title: "Tags search" do
          search_request = SearchRequest.from_request(params)
          results = Search.execute(:tags, params)

          if results.present?
            docs = results.map do |model|
              DocResult.new(
                doc_id: model.nid,
                doc_type: 'TAGS',
                doc_url: model.path,
                doc_title: model.title
              )
            end

            DocList.new(docs, search_request)
          else
            DocList.new('', search_request)
          end
        end
      end

      # Request URL should be /api/srch/taglocations?nwlat=200.0&selat=0.0&nwlng=0.0&selng=200.0[&tag=awesome]
      desc 'Perform a search of documents having nearby latitude and longitude tag values', hidden: false,
                                                                                            is_array: false,
                                                                                            nickname: 'search_tag_locations'

      params do
        use :geographical, :additional, :period, :sorting, :ordering
      end
      get :taglocations do
        search_request = SearchRequest.from_request(params)
        results = Search.execute(:taglocations, params)

        if results.present?
          docs = results.map do |model|
            doctype = model.has_power_tag('question') ? 'QUESTION' : 'NOTE'
            doctype = 'WIKI' if model.type == 'page'
            DocResult.new(
              doc_id: model.nid,
              doc_type: doctype,
              doc_url: model.path(:items),
              doc_title: model.title,
              doc_author: model.user.username,
              doc_image_url: model.images.empty? ? 0 : model.images.first.path,
              score: model.comments.length,
              latitude: model.lat,
              longitude: model.lon,
              blurred: model.blurred?,
              place_name: model.has_power_tag('place') ? model.power_tag('place') : '',
              created_at: model.created_at
              # time_since: distance_of_time_in_words(model.created_at, Time.current, { include_seconds: false, scope: 'datetime.time_ago_in_words' }),  # works, but really slows down the search results
              # comment_count: model.comments_viewable_by(current_user).length  # causes an error because of current_user?
            )
          end
          DocList.new(docs, search_request)
        else
          DocList.new('', search_request)
        end
      end

      # Request URL should be /api/srch/nearbyPeople?nwlat=200.0&selat=0.0&nwlng=0.0&selng=200.0[&tag=awesome&sort_by=recent]
      desc 'Perform a search to show people nearby a given location',  hidden: false,
                                                                       is_array: false,
                                                                       nickname: 'search_nearby_people'
      params do
        use :geographical, :additional, :field, :period, :sorting, :ordering
      end
      get :nearbyPeople do
        search_request = SearchRequest.from_request(params)
        results = Search.execute(:nearbyPeople, params)

        if results.present?
          docs = results.map do |model|
            DocResult.new(
              doc_id: model.id,
              doc_type: 'PLACES',
              doc_url: model.path,
              doc_title: model.username,
              latitude: model.lat,
              longitude: model.lon,
              blurred: model.blurred?,
              created_at: model.created_at,
              doc_image_url: model.profile_image || ""
            )
          end
          DocList.new(docs, search_request)
        else
          DocList.new('', search_request)
        end
      end

      # Request URL should be /api/srch/places?query=QRY
      desc 'Perform a search of places',           hidden: false,
                                                   is_array: false,
                                                   nickname: 'search_places'

      params do
        use :common
      end
      get :places do
        search_request = SearchRequest.from_request(params)
        results = Search.execute(:places, params)

        if results.present?
          docs = results.map do |model|
            DocResult.new(
              doc_id: model.nid,
              doc_type: 'PLACES',
              doc_url: model.path,
              doc_title: model.title
            )
          end

          DocList.new(docs, search_request)
        else
          DocList.new('', search_request)
        end
      end
    end

    def self.execute(endpoint, params)
      search_type = endpoint
      search_criteria = SearchCriteria.new(params)
      search_criteria.validate_period_from_to
      if search_criteria.valid?
        ExecuteSearch.new.by(search_type, search_criteria)
      else
        []
      end
    end
  end
end