Merge branch 'feat/linear-backend' into feature/cw-3271

This commit is contained in:
Muhsin Keloth
2024-05-22 12:13:41 +05:30
committed by GitHub
8 changed files with 75 additions and 74 deletions
@@ -3,29 +3,29 @@ class Api::V1::Accounts::Integrations::LinearController < Api::V1::Accounts::Bas
def teams
teams = linear_processor_service.teams
if teams.is_a?(Hash) && teams[:error]
if teams[:error]
render json: { error: teams[:error] }, status: :unprocessable_entity
else
render json: teams, status: :ok
render json: teams[:data], status: :ok
end
end
def team_entities
team_id = permitted_params[:team_id]
entites = linear_processor_service.team_entities(team_id)
if entites.is_a?(Hash) && entites[:error]
render json: { error: entites[:error] }, status: :unprocessable_entity
team_entities = linear_processor_service.team_entities(team_id)
if team_entities[:error]
render json: { error: team_entities[:error] }, status: :unprocessable_entity
else
render json: entites, status: :ok
render json: team_entities[:data], status: :ok
end
end
def create_issue
issue = linear_processor_service.create_issue(permitted_params)
if issue.is_a?(Hash) && issue[:error]
if issue[:error]
render json: { error: issue[:error] }, status: :unprocessable_entity
else
render json: issue, status: :ok
render json: issue[:data], status: :ok
end
end
@@ -33,10 +33,10 @@ class Api::V1::Accounts::Integrations::LinearController < Api::V1::Accounts::Bas
issue_id = permitted_params[:issue_id]
title = permitted_params[:title]
issue = linear_processor_service.link_issue(conversation_link, issue_id, title)
if issue.is_a?(Hash) && issue[:error]
if issue[:error]
render json: { error: issue[:error] }, status: :unprocessable_entity
else
render json: issue, status: :ok
render json: issue[:data], status: :ok
end
end
@@ -44,20 +44,20 @@ class Api::V1::Accounts::Integrations::LinearController < Api::V1::Accounts::Bas
link_id = permitted_params[:link_id]
issue = linear_processor_service.unlink_issue(link_id)
if issue.is_a?(Hash) && issue[:error]
if issue[:error]
render json: { error: issue[:error] }, status: :unprocessable_entity
else
render json: issue, status: :ok
render json: issue[:data], status: :ok
end
end
def linked_issue
issues = linear_processor_service.linked_issue(conversation_link)
issues = linear_processor_service.linked_issues(conversation_link)
if issues.is_a?(Hash) && issues[:error]
if issues[:error]
render json: { error: issues[:error] }, status: :unprocessable_entity
else
render json: issues, status: :ok
render json: issues[:data], status: :ok
end
end
@@ -66,10 +66,10 @@ class Api::V1::Accounts::Integrations::LinearController < Api::V1::Accounts::Bas
term = params[:q]
issues = linear_processor_service.search_issue(term)
if issues.is_a?(Hash) && issues[:error]
if issues[:error]
render json: { error: issues[:error] }, status: :unprocessable_entity
else
render json: issues, status: :ok
render json: issues[:data], status: :ok
end
end
+20 -16
View File
@@ -3,9 +3,9 @@ class Integrations::Linear::ProcessorService
def teams
response = linear_client.teams
return response if response[:error]
return { error: response[:error] } if response[:error]
response['teams']['nodes'].map(&:as_json)
{ data: response['teams']['nodes'].map(&:as_json) }
end
def team_entities(team_id)
@@ -13,10 +13,12 @@ class Integrations::Linear::ProcessorService
return response if response[:error]
{
users: response['users']['nodes'].map(&:as_json),
projects: response['projects']['nodes'].map(&:as_json),
states: response['workflowStates']['nodes'].map(&:as_json),
labels: response['issueLabels']['nodes'].map(&:as_json)
data: {
users: response['users']['nodes'].map(&:as_json),
projects: response['projects']['nodes'].map(&:as_json),
states: response['workflowStates']['nodes'].map(&:as_json),
labels: response['issueLabels']['nodes'].map(&:as_json)
}
}
end
@@ -25,8 +27,8 @@ class Integrations::Linear::ProcessorService
return response if response[:error]
{
id: response['issueCreate']['issue']['id'],
title: response['issueCreate']['issue']['title']
data: { id: response['issueCreate']['issue']['id'],
title: response['issueCreate']['issue']['title'] }
}
end
@@ -35,9 +37,11 @@ class Integrations::Linear::ProcessorService
return response if response[:error]
{
id: issue_id,
link: link,
link_id: response.with_indifferent_access[:attachmentLinkURL][:attachment][:id]
data: {
id: issue_id,
link: link,
link_id: response.with_indifferent_access[:attachmentLinkURL][:attachment][:id]
}
}
end
@@ -46,7 +50,7 @@ class Integrations::Linear::ProcessorService
return response if response[:error]
{
link_id: link_id
data: { link_id: link_id }
}
end
@@ -55,14 +59,14 @@ class Integrations::Linear::ProcessorService
return response if response[:error]
response['searchIssues']['nodes'].map(&:as_json)
{ data: response['searchIssues']['nodes'].map(&:as_json) }
end
def linked_issue(url)
response = linear_client.linked_issue(url)
def linked_issues(url)
response = linear_client.linked_issues(url)
return response if response[:error]
response['attachmentsForURL']['nodes'].map(&:as_json)
{ data: response['attachmentsForURL']['nodes'].map(&:as_json) }
end
private
+8 -11
View File
@@ -1,6 +1,3 @@
require_relative 'linear_queries'
require_relative 'linear_mutations'
class Linear
BASE_URL = 'https://api.linear.app/graphql'.freeze
PRIORITY_LEVELS = (0..4).to_a
@@ -12,7 +9,7 @@ class Linear
def teams
query = {
query: LinearQueries::TEAMS_QUERY
query: Linear::Queries::TEAMS_QUERY
}
response = post(query)
process_response(response)
@@ -22,7 +19,7 @@ class Linear
raise ArgumentError, 'Missing team id' if team_id.blank?
query = {
query: LinearQueries.team_entities_query(team_id)
query: Linear::Queries.team_entities_query(team_id)
}
response = post(query)
process_response(response)
@@ -32,17 +29,17 @@ class Linear
raise ArgumentError, 'Missing search term' if term.blank?
query = {
query: LinearQueries.search_issue(term)
query: Linear::Queries.search_issue(term)
}
response = post(query)
process_response(response)
end
def linked_issue(url)
def linked_issues(url)
raise ArgumentError, 'Missing link' if url.blank?
query = {
query: LinearQueries.linked_issue(url)
query: Linear::Queries.linked_issues(url)
}
response = post(query)
process_response(response)
@@ -61,7 +58,7 @@ class Linear
priority: params[:priority],
labelIds: params[:label_ids]
}.compact
mutation = LinearMutations.issue_create(variables)
mutation = Linear::Mutations.issue_create(variables)
response = post({ query: mutation })
process_response(response)
end
@@ -71,7 +68,7 @@ class Linear
raise ArgumentError, 'Missing issue id' if issue_id.blank?
payload = {
query: LinearMutations.issue_link(issue_id, link, title)
query: Linear::Mutations.issue_link(issue_id, link, title)
}
response = post(payload)
process_response(response)
@@ -81,7 +78,7 @@ class Linear
raise ArgumentError, 'Missing link id' if link_id.blank?
payload = {
query: LinearMutations.unlink_issue(link_id)
query: Linear::Mutations.unlink_issue(link_id)
}
response = post(payload)
process_response(response)
@@ -1,4 +1,4 @@
module LinearMutations
module Linear::Mutations
def self.graphql_value(value)
case value
when String
@@ -1,4 +1,4 @@
module LinearQueries
module Linear::Queries
TEAMS_QUERY = <<~GRAPHQL.freeze
query {
teams {
@@ -60,7 +60,7 @@ module LinearQueries
GRAPHQL
end
def self.linked_issue(url)
def self.linked_issues(url)
<<~GRAPHQL
query {
attachmentsForURL(url: "#{url}") {
@@ -15,7 +15,7 @@ RSpec.describe 'Linear Integration API', type: :request do
describe 'GET /api/v1/accounts/:account_id/integrations/linear/teams' do
context 'when it is an authenticated user' do
context 'when data is retrieved successfully' do
let(:teams_data) { [{ 'id' => 'team1', 'name' => 'Team One' }] }
let(:teams_data) { { data: [{ 'id' => 'team1', 'name' => 'Team One' }] } }
it 'returns team data' do
allow(processor_service).to receive(:teams).and_return(teams_data)
@@ -46,12 +46,12 @@ RSpec.describe 'Linear Integration API', type: :request do
context 'when it is an authenticated user' do
context 'when data is retrieved successfully' do
let(:team_entities_data) do
{
{ data: {
users: [{ 'id' => 'user1', 'name' => 'User One' }],
projects: [{ 'id' => 'project1', 'name' => 'Project One' }],
states: [{ 'id' => 'state1', 'name' => 'State One' }],
labels: [{ 'id' => 'label1', 'name' => 'Label One' }]
}
} }
end
it 'returns team entities data' do
@@ -96,7 +96,7 @@ RSpec.describe 'Linear Integration API', type: :request do
context 'when it is an authenticated user' do
context 'when the issue is created successfully' do
let(:created_issue) { { 'id' => 'issue1', 'title' => 'Sample Issue' } }
let(:created_issue) { { data: { 'id' => 'issue1', 'title' => 'Sample Issue' } } }
it 'returns the created issue' do
allow(processor_service).to receive(:create_issue).with(issue_params.stringify_keys).and_return(created_issue)
@@ -131,7 +131,7 @@ RSpec.describe 'Linear Integration API', type: :request do
context 'when it is an authenticated user' do
context 'when the issue is linked successfully' do
let(:linked_issue) { { 'id' => 'issue1', 'link' => 'https://linear.app/issue1' } }
let(:linked_issue) { { data: { 'id' => 'issue1', 'link' => 'https://linear.app/issue1' } } }
it 'returns the linked issue' do
allow(processor_service).to receive(:link_issue).with(link, issue_id, title).and_return(linked_issue)
@@ -163,7 +163,7 @@ RSpec.describe 'Linear Integration API', type: :request do
context 'when it is an authenticated user' do
context 'when the issue is unlinked successfully' do
let(:unlinked_issue) { { 'id' => 'issue1', 'link' => 'https://linear.app/issue1' } }
let(:unlinked_issue) { { data: { 'id' => 'issue1', 'link' => 'https://linear.app/issue1' } } }
it 'returns the unlinked issue' do
allow(processor_service).to receive(:unlink_issue).with(link_id).and_return(unlinked_issue)
@@ -195,7 +195,7 @@ RSpec.describe 'Linear Integration API', type: :request do
context 'when it is an authenticated user' do
context 'when search is successful' do
let(:search_results) { [{ 'id' => 'issue1', 'title' => 'Sample Issue' }] }
let(:search_results) { { data: [{ 'id' => 'issue1', 'title' => 'Sample Issue' }] } }
it 'returns search results' do
allow(processor_service).to receive(:search_issue).with(term).and_return(search_results)
@@ -228,10 +228,10 @@ RSpec.describe 'Linear Integration API', type: :request do
context 'when it is an authenticated user' do
context 'when linked issue is found' do
let(:linked_issue) { [{ 'id' => 'issue1', 'title' => 'Sample Issue' }] }
let(:linked_issue) { { data: [{ 'id' => 'issue1', 'title' => 'Sample Issue' }] } }
it 'returns linked issue' do
allow(processor_service).to receive(:linked_issue).with(link).and_return(linked_issue)
allow(processor_service).to receive(:linked_issues).with(link).and_return(linked_issue)
get "/api/v1/accounts/#{account.id}/integrations/linear/linked_issue",
params: { conversation_id: conversation.display_id },
headers: agent.create_new_auth_token,
@@ -243,7 +243,7 @@ RSpec.describe 'Linear Integration API', type: :request do
context 'when linked issue is not found' do
it 'returns error message' do
allow(processor_service).to receive(:linked_issue).with(link).and_return(error: 'error message')
allow(processor_service).to receive(:linked_issues).with(link).and_return(error: 'error message')
get "/api/v1/accounts/#{account.id}/integrations/linear/linked_issue",
params: { conversation_id: conversation.display_id },
headers: agent.create_new_auth_token,
@@ -20,7 +20,7 @@ describe Integrations::Linear::ProcessorService do
it 'returns parsed team data' do
allow(linear_client).to receive(:teams).and_return(teams_response)
result = service.teams
expect(result).to contain_exactly({ 'id' => 'team1', 'name' => 'Team One' })
expect(result).to eq({ data: [{ 'id' => 'team1', 'name' => 'Team One' }] })
end
end
@@ -50,10 +50,10 @@ describe Integrations::Linear::ProcessorService do
it 'returns parsed entity data' do
allow(linear_client).to receive(:team_entities).with(team_id).and_return(entities_response)
result = service.team_entities(team_id)
expect(result).to have_key(:users)
expect(result).to have_key(:projects)
expect(result).to have_key(:states)
expect(result).to have_key(:labels)
expect(result).to eq({ :data => { :users =>
[{ 'id' => 'user1', 'name' => 'User One' }],
:projects => [{ 'id' => 'project1', 'name' => 'Project One' }],
:states => [], :labels => [{ 'id' => 'bug', 'name' => 'Bug' }] } })
end
end
@@ -89,7 +89,7 @@ describe Integrations::Linear::ProcessorService do
it 'returns parsed issue data' do
allow(linear_client).to receive(:create_issue).with(params).and_return(issue_response)
result = service.create_issue(params)
expect(result).to eq({ id: 'issue1', title: 'Issue title' })
expect(result).to eq({ data: { id: 'issue1', title: 'Issue title' } })
end
end
@@ -109,7 +109,7 @@ describe Integrations::Linear::ProcessorService do
let(:issue_id) { 'issue1' }
let(:title) { 'Title' }
let(:link_issue_response) { { id: issue_id, link: link, 'attachmentLinkURL': { 'attachment': { 'id': 'attachment1' } } } }
let(:link_response) { { id: issue_id, link: link, link_id: 'attachment1' } }
let(:link_response) { { data: { id: issue_id, link: link, link_id: 'attachment1' } } }
context 'when Linear client returns valid data' do
it 'returns parsed link data' do
@@ -132,7 +132,7 @@ describe Integrations::Linear::ProcessorService do
describe '#unlink_issue' do
let(:link_id) { 'attachment1' }
let(:unlink_response) { { link_id: link_id } }
let(:unlink_response) { { data: { link_id: link_id } } }
context 'when Linear client returns valid data' do
it 'returns parsed unlink data' do
@@ -165,7 +165,7 @@ describe Integrations::Linear::ProcessorService 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' })
expect(result).to eq({ :data => [{ 'description' => 'Issue description', 'id' => 'issue1', 'title' => 'Issue title' }] })
end
end
@@ -180,7 +180,7 @@ describe Integrations::Linear::ProcessorService do
end
end
describe '#linked_issue' do
describe '#linked_issues' do
let(:url) { 'https://example.com' }
let(:linked_response) do
{
@@ -190,9 +190,9 @@ describe Integrations::Linear::ProcessorService do
context 'when Linear client returns valid data' do
it 'returns parsed linked data' do
allow(linear_client).to receive(:linked_issue).with(url).and_return(linked_response)
result = service.linked_issue(url)
expect(result).to contain_exactly({ 'id' => 'attachment1', 'issue' => { 'id' => 'issue1' } })
allow(linear_client).to receive(:linked_issues).with(url).and_return(linked_response)
result = service.linked_issues(url)
expect(result).to eq({ :data => [{ 'id' => 'attachment1', 'issue' => { 'id' => 'issue1' } }] })
end
end
@@ -200,8 +200,8 @@ describe Integrations::Linear::ProcessorService do
let(:error_response) { { error: 'Some error message' } }
it 'returns the error' do
allow(linear_client).to receive(:linked_issue).with(url).and_return(error_response)
result = service.linked_issue(url)
allow(linear_client).to receive(:linked_issues).with(url).and_return(error_response)
result = service.linked_issues(url)
expect(result).to eq(error_response)
end
end
+2 -2
View File
@@ -281,7 +281,7 @@ describe Linear do
end
it 'returns linked issues' do
response = linear_client.linked_issue('app.chatwoot.com')
response = linear_client.linked_issues('app.chatwoot.com')
expect(response).to eq({ 'linkedIssue' => { 'id' => 'issue1', 'title' => 'Title' } })
end
end
@@ -294,7 +294,7 @@ describe Linear do
end
it 'raises an exception' do
response = linear_client.linked_issue('app.chatwoot.com')
response = linear_client.linked_issues('app.chatwoot.com')
expect(response).to eq({ :error => { 'errors' => [{ 'message' => 'Error retrieving data' }] }, :error_code => 422 })
end
end