From 5e1dbfb64dad292207dfdfc77cbc27a7fea90bbe Mon Sep 17 00:00:00 2001 From: Muhsin Keloth Date: Thu, 9 May 2024 22:28:47 +0530 Subject: [PATCH] feat: search issue API --- .../integrations/linear_controller.rb | 12 +++++ config/routes.rb | 1 + lib/integrations/linear/processor_service.rb | 8 +++ lib/linear.rb | 6 +++ lib/linear_queries.rb | 14 ++++++ .../integrations/linear_controller_spec.rb | 32 ++++++++++++ .../linear/processor_service_spec.rb | 50 +++++++++++++++++++ spec/lib/linear_spec.rb | 30 +++++++++++ 8 files changed, 153 insertions(+) diff --git a/app/controllers/api/v1/accounts/integrations/linear_controller.rb b/app/controllers/api/v1/accounts/integrations/linear_controller.rb index a8198a770..9d1fbf25f 100644 --- a/app/controllers/api/v1/accounts/integrations/linear_controller.rb +++ b/app/controllers/api/v1/accounts/integrations/linear_controller.rb @@ -49,6 +49,18 @@ class Api::V1::Accounts::Integrations::LinearController < Api::V1::Accounts::Bas end end + def search_issue + render json: { error: 'Specify search string with parameter q' }, status: :unprocessable_entity if params[:q].blank? && return + + term = params[:q] + issues = linear_processor_service.search_issue(term) + if issues.is_a?(Hash) && issues[:error] + render json: { error: issues[:error] }, status: :unprocessable_entity + else + render json: issues, status: :ok + end + end + private def linear_processor_service diff --git a/config/routes.rb b/config/routes.rb index eb57fe027..26a6322da 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -234,6 +234,7 @@ Rails.application.routes.draw do post :create_issue post :link_issue post :unlink_issue + get :search_issue end end end diff --git a/lib/integrations/linear/processor_service.rb b/lib/integrations/linear/processor_service.rb index 28ef9d638..83a4e8b4f 100644 --- a/lib/integrations/linear/processor_service.rb +++ b/lib/integrations/linear/processor_service.rb @@ -50,6 +50,14 @@ class Integrations::Linear::ProcessorService } end + def search_issue(term) + response = linear_client.search_issue(term) + + return response if response[:error] + + response['searchIssues']['nodes'].map(&:as_json) + end + private def linear_hook diff --git a/lib/linear.rb b/lib/linear.rb index 424966a5c..8536f1196 100644 --- a/lib/linear.rb +++ b/lib/linear.rb @@ -29,6 +29,12 @@ class Linear execute_query(LinearQueries.team_entites_query(team_id)) end + def search_issue(term) + raise ArgumentError, 'Missing search term' if term.blank? + + execute_query(LinearQueries.search_issue(term)) + end + def create_issue(params) validate_team_and_title(params) validate_priority(params[:priority]) diff --git a/lib/linear_queries.rb b/lib/linear_queries.rb index d4d349600..90eae3d9a 100644 --- a/lib/linear_queries.rb +++ b/lib/linear_queries.rb @@ -44,4 +44,18 @@ module LinearQueries } GRAPHQL end + + def self.search_issue(term) + <<~GRAPHQL + query { + searchIssues(term: "#{term}") { + nodes { + id + title + description + } + } + } + GRAPHQL + end end diff --git a/spec/controllers/api/v1/accounts/integrations/linear_controller_spec.rb b/spec/controllers/api/v1/accounts/integrations/linear_controller_spec.rb index 79c74713c..25fbd1eeb 100644 --- a/spec/controllers/api/v1/accounts/integrations/linear_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/integrations/linear_controller_spec.rb @@ -187,4 +187,36 @@ RSpec.describe 'Linear Integration API', type: :request do end end end + + describe 'GET /api/v1/accounts/:account_id/integrations/linear/search_issue' do + let(:term) { 'issue' } + + context 'when it is an authenticated user' do + context 'when search is successful' do + let(:search_results) { [{ 'id' => 'issue1', 'title' => 'Sample Issue' }] } + + it 'returns search results' do + allow(processor_service).to receive(:search_issue).with(term).and_return(search_results) + get "/api/v1/accounts/#{account.id}/integrations/linear/search_issue", + params: { q: term }, + headers: agent.create_new_auth_token, + as: :json + expect(response).to have_http_status(:ok) + expect(response.body).to include('Sample Issue') + end + end + + context 'when search fails' do + it 'returns error message' do + allow(processor_service).to receive(:search_issue).with(term).and_return(error: 'error message') + get "/api/v1/accounts/#{account.id}/integrations/linear/search_issue", + params: { q: term }, + headers: agent.create_new_auth_token, + as: :json + expect(response).to have_http_status(:unprocessable_entity) + expect(response.body).to include('error message') + end + end + end + end end diff --git a/spec/lib/integrations/linear/processor_service_spec.rb b/spec/lib/integrations/linear/processor_service_spec.rb index 470a7244e..aeb46c617 100644 --- a/spec/lib/integrations/linear/processor_service_spec.rb +++ b/spec/lib/integrations/linear/processor_service_spec.rb @@ -128,4 +128,54 @@ describe Integrations::Linear::ProcessorService do end end end + + describe '#unlink_issue' do + let(:link_id) { 'attachment1' } + let(:unlink_response) { { link_id: link_id } } + + context 'when Linear client returns valid data' do + it 'returns parsed unlink data' do + allow(linear_client).to receive(:unlink_issue).with(link_id).and_return(unlink_response) + result = service.unlink_issue(link_id) + expect(result).to eq(unlink_response) + end + end + + context 'when Linear client returns an error' do + let(:error_response) { { error: 'Some error message' } } + + it 'returns the error' do + allow(linear_client).to receive(:unlink_issue).with(link_id).and_return(error_response) + result = service.unlink_issue(link_id) + expect(result).to eq(error_response) + end + end + end + + describe '#search_issue' do + let(:term) { 'search term' } + let(:search_response) do + { + 'searchIssues' => { 'nodes' => [{ 'id' => 'issue1', 'title' => 'Issue title', 'description' => 'Issue description' }] } + } + end + + context 'when Linear client returns valid data' do + it 'returns parsed search data' do + allow(linear_client).to receive(:search_issue).with(term).and_return(search_response) + result = service.search_issue(term) + expect(result).to contain_exactly({ 'id' => 'issue1', 'title' => 'Issue title', 'description' => 'Issue description' }) + end + end + + context 'when Linear client returns an error' do + let(:error_response) { { error: 'Some error message' } } + + it 'returns the error' do + allow(linear_client).to receive(:search_issue).with(term).and_return(error_response) + result = service.search_issue(term) + expect(result).to eq(error_response) + end + end + end end diff --git a/spec/lib/linear_spec.rb b/spec/lib/linear_spec.rb index 943257995..5ea002310 100644 --- a/spec/lib/linear_spec.rb +++ b/spec/lib/linear_spec.rb @@ -249,4 +249,34 @@ describe Linear do end end end + + context 'when querying issues' do + let(:term) { 'term' } + + context 'when the API response is success' do + before do + linear_client.instance_variable_set(:@client, client) + stub_request(:post, url) + .to_return(status: 200, body: { data: { searchIssues: { nodes: [{ id: 'issue1', title: 'Title' }] } } }.to_json) + end + + it 'returns issues' do + response = linear_client.search_issue(term) + expect(response).to eq({ 'searchIssues' => { 'nodes' => [{ 'id' => 'issue1', 'title' => 'Title' }] } }) + end + end + + context 'when the API response is an error' do + before do + linear_client.instance_variable_set(:@client, client) + stub_request(:post, url) + .to_return(status: 422, body: { errors: [{ message: 'Error retrieving data' }] }.to_json) + end + + it 'raises an exception' do + response = linear_client.search_issue(term) + expect(response).to eq({ :error => 'Error: the server responded with status 422' }) + end + end + end end