From 7dba616e4e9e9e0319b809669513fce920e8b0bb Mon Sep 17 00:00:00 2001 From: Hank Grabowski Date: Sat, 1 Dec 2018 16:08:07 -0500 Subject: [PATCH] Search API Endpoint and unit test complete --- app/controllers/api/v1/search_controller.rb | 31 ++++ config/locales/diaspora/en.yml | 2 + config/routes.rb | 2 + .../integration/api/search_controller_spec.rb | 155 ++++++++++++++++++ 4 files changed, 190 insertions(+) create mode 100644 app/controllers/api/v1/search_controller.rb create mode 100644 spec/integration/api/search_controller_spec.rb diff --git a/app/controllers/api/v1/search_controller.rb b/app/controllers/api/v1/search_controller.rb new file mode 100644 index 000000000..dd56e1ca6 --- /dev/null +++ b/app/controllers/api/v1/search_controller.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module Api + module V1 + class SearchController < Api::V1::BaseController + before_action do + require_access_token %w[read] + end + + rescue_from ActionController::ParameterMissing, RuntimeError do + render json: I18n.t("api.endpoint_errors.search.cant_process"), status: :unprocessable_entity + end + + def user_index + parameters = params.permit(:tag, :name_or_handle) + raise RuntimeError if parameters.keys.length != 1 + people = if params.has_key?(:tag) + Person.profile_tagged_with(params[:tag]) + else + Person.search(params[:name_or_handle], current_user) + end + render json: people.map {|p| PersonPresenter.new(p).as_api_json } + end + + def post_index + posts = Stream::Tag.new(current_user, params.require(:tag)).posts + render json: posts.map {|p| PostPresenter.new(p).as_api_response } + end + end + end +end diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml index 86fb61963..63236af61 100644 --- a/config/locales/diaspora/en.yml +++ b/config/locales/diaspora/en.yml @@ -985,6 +985,8 @@ en: users: cant_update: "Failed to update the user settings" not_found: "User not found" + search: + cant_process: "Search request could not be processed" tags: cant_process: "Failed to process the tag followings request" diff --git a/config/routes.rb b/config/routes.rb index 8dd8e4e96..2f19647d7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -249,6 +249,8 @@ Rails.application.routes.draw do get :posts end resources :tag_followings, only: %i[index create destroy] + get "search/users" => "search#user_index", :as => "user_index" + get "search/posts" => "search#post_index", :as => "post_index" get "streams/activity" => "streams#activity", :as => "activity_stream" get "streams/main" => "streams#multi", :as => "stream" get "streams/tags" => "streams#followed_tags", :as => "followed_tags_stream" diff --git a/spec/integration/api/search_controller_spec.rb b/spec/integration/api/search_controller_spec.rb new file mode 100644 index 000000000..13276277b --- /dev/null +++ b/spec/integration/api/search_controller_spec.rb @@ -0,0 +1,155 @@ +# frozen_string_literal: true + +require "spec_helper" + +describe Api::V1::SearchController do + let(:auth) { FactoryGirl.create(:auth_with_read_and_write) } + let!(:access_token) { auth.create_access_token.to_s } + let(:auth_read_only) { FactoryGirl.create(:auth_with_read) } + let!(:access_token_read_only) { auth_read_only.create_access_token.to_s } + + describe "#user_index" do + before do + @searchable_user = FactoryGirl.create( + :person, + diaspora_handle: "findable@example.org", + profile: FactoryGirl.build(:profile, first_name: "Terry", last_name: "Smith") + ) + + @closed_user = FactoryGirl.create( + :person, + closed_account: true, + profile: FactoryGirl.build(:profile, first_name: "Closed", last_name: "Account") + ) + @unsearchable_user = FactoryGirl.create( + :person, + diaspora_handle: "unsearchable@example.org", + profile: FactoryGirl.build( + :profile, + first_name: "Unsearchable", + last_name: "Person", + searchable: false + ) + ) + end + + it "succeeds by tag" do + get( + "/api/v1/search/users", + params: {tag: "one", access_token: access_token} + ) + expect(response.status).to eq(200) + users = JSON.parse(response.body) + expect(users.length).to eq(14) + end + + it "succeeds by name" do + get( + "/api/v1/search/users", + params: {name_or_handle: "Terry", access_token: access_token} + ) + expect(response.status).to eq(200) + users = JSON.parse(response.body) + expect(users.length).to eq(1) + end + + it "succeeds by handle" do + get( + "/api/v1/search/users", + params: {name_or_handle: "findable", access_token: access_token} + ) + expect(response.status).to eq(200) + users = JSON.parse(response.body) + expect(users.length).to eq(1) + end + + it "doesn't return closed accounts" do + get( + "/api/v1/search/users", + params: {name_or_handle: "Closed", access_token: access_token} + ) + expect(response.status).to eq(200) + users = JSON.parse(response.body) + expect(users.length).to eq(0) + end + + it "doesn't return hidden accounts" do + get( + "/api/v1/search/users", + params: {name_or_handle: "unsearchable@example.org", access_token: access_token} + ) + expect(response.status).to eq(200) + users = JSON.parse(response.body) + expect(users.length).to eq(0) + end + + it "fails if ask for both" do + get( + "/api/v1/search/users", + params: {tag: "tag1", name_or_handle: "name", access_token: access_token} + ) + expect(response.status).to eq(422) + expect(response.body).to eq(I18n.t("api.endpoint_errors.search.cant_process")) + end + + it "fails with no fields" do + get( + "/api/v1/search/users", + params: {access_token: access_token} + ) + expect(response.status).to eq(422) + expect(response.body).to eq(I18n.t("api.endpoint_errors.search.cant_process")) + end + + it "fails with bad credentials" do + get( + "/api/v1/search/users", + params: {tag: "tag1", access_token: "999_999_999"} + ) + expect(response.status).to eq(401) + end + end + + describe "post_index" do + before do + @user_post = auth.user.post( + :status_message, + text: "This is a status message #tag1 #tag2", + public: true + ) + + @eve_post = eve.post( + :status_message, + text: "This is Eve's status message #tag2 #tag3", + public: true + ) + end + + it "succeeds by tag" do + get( + "/api/v1/search/posts", + params: {tag: "tag2", access_token: access_token} + ) + expect(response.status).to eq(200) + posts = JSON.parse(response.body) + expect(posts.length).to eq(2) + end + + it "fails with missing parameters" do + get( + "/api/v1/search/posts", + params: {access_token: access_token} + ) + expect(response.status).to eq(422) + expect(response.body).to eq(I18n.t("api.endpoint_errors.search.cant_process")) + end + + it "fails with bad credentials" do + get( + "/api/v1/search/users", + params: {tag: "tag1", access_token: "999_999_999"} + ) + expect(response.status).to eq(401) + end + end +end