Fixes #3661 - FreshDesk Import Error - undefined method `body' for 10:Integer.

This commit is contained in:
Dominik Klein 2021-07-28 16:40:08 +02:00 committed by Thorsten Eckel
parent 7f9c477cf4
commit 0ded6e542b
9 changed files with 108 additions and 6 deletions

View file

@ -8,7 +8,7 @@ class Sequencer
def self.sequence def self.sequence
[ [
'Sequencer::Unit::Import::Freshdesk::Request', 'Import::Freshdesk::Request',
'Import::Freshdesk::Resources', 'Import::Freshdesk::Resources',
'Import::Freshdesk::ModelClass', 'Import::Freshdesk::ModelClass',
'Import::Freshdesk::Perform', 'Import::Freshdesk::Perform',

View file

@ -8,7 +8,7 @@ class Sequencer
def self.sequence def self.sequence
[ [
'Sequencer::Unit::Import::Freshdesk::Request', 'Import::Freshdesk::Request',
'Import::Freshdesk::Resources', 'Import::Freshdesk::Resources',
'Import::Freshdesk::ModelClass', 'Import::Freshdesk::ModelClass',
'Import::Freshdesk::Perform', 'Import::Freshdesk::Perform',

View file

@ -33,6 +33,8 @@ class Sequencer
end end
def sum_deeply(existing:, additions:) def sum_deeply(existing:, additions:)
return existing if additions.nil?
existing.merge(additions) do |_key, oldval, newval| existing.merge(additions) do |_key, oldval, newval|
if oldval.is_a?(Hash) || newval.is_a?(Hash) if oldval.is_a?(Hash) || newval.is_a?(Hash)
sum_deeply( sum_deeply(

View file

@ -6,6 +6,9 @@ class Sequencer
module Freshdesk module Freshdesk
class ObjectCount < Sequencer::Unit::Common::Provider::Attribute class ObjectCount < Sequencer::Unit::Common::Provider::Attribute
include ::Sequencer::Unit::Import::Common::Model::Statistics::Mixin::EmptyDiff include ::Sequencer::Unit::Import::Common::Model::Statistics::Mixin::EmptyDiff
prepend ::Sequencer::Unit::Import::Common::Model::Mixin::Skip::Action
skip_action :skipped, :failed
uses :model_class, :resources uses :model_class, :resources

View file

@ -5,6 +5,9 @@ class Sequencer
module Import module Import
module Freshdesk module Freshdesk
class Perform < Sequencer::Unit::Base class Perform < Sequencer::Unit::Base
prepend ::Sequencer::Unit::Import::Common::Model::Mixin::Skip::Action
skip_action :skipped, :failed
uses :resources, :object, :import_job, :dry_run, :field_map, :id_map uses :resources, :object, :import_job, :dry_run, :field_map, :id_map

View file

@ -18,6 +18,8 @@ class Sequencer
rescue Net::HTTPClientError => e rescue Net::HTTPClientError => e
handle_exception e, iteration handle_exception e, iteration
end end
nil
end end
def handle_error(response, iteration) def handle_error(response, iteration)

View file

@ -5,6 +5,7 @@ class Sequencer
module Import module Import
module Freshdesk module Freshdesk
class Resources < Sequencer::Unit::Common::Provider::Named class Resources < Sequencer::Unit::Common::Provider::Named
include ::Sequencer::Unit::Import::Common::Model::Mixin::HandleFailure
uses :response uses :response
@ -12,6 +13,9 @@ class Sequencer
def resources def resources
JSON.parse(response.body) JSON.parse(response.body)
rescue => e
logger.error "Won't be continued, because no response is available."
handle_failure(e)
end end
end end
end end

View file

@ -24,24 +24,47 @@ class Sequencer
field_map: field_map, field_map: field_map,
id_map: id_map, id_map: id_map,
}, },
expecting: [:response]) expecting: %i[action response])
break if result[:response].header['link'].blank? break if iteration_should_stop?(result)
end end
end end
def request_params def request_params
{ {
page: iteration + 1, page: page,
} }
end end
def page
iteration + 1
end
def object def object
self.class.name.demodulize.singularize @object ||= self.class.name.demodulize.singularize
end end
def sequence_name def sequence_name
raise NotImplementedError raise NotImplementedError
end end
private
def iteration_should_stop?(result)
return true if result[:action] == :failed
return true if result[:response].header['link'].blank?
max_page_reached?
end
# https://github.com/zammad/zammad/issues/3661
# https://developers.freshdesk.com/api/#list_all_tickets
def max_page_reached?
return false if object != 'Ticket'
return false if page <= 300
logger.warn "Reached max Freshdesk API page number #{page} for #{object}. Stopping further requests to prevent errors."
true
end
end end
end end
end end

View file

@ -0,0 +1,65 @@
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
require 'rails_helper'
RSpec.describe ::Sequencer::Sequence::Import::Freshdesk::GenericObject, sequencer: :sequence, db_strategy: 'reset' do
context 'when importing group list with generic object' do
let(:resources_payloud) do
[
{
'id' => 80_000_374_715,
'name' => 'QA',
'description' => 'Members of the QA team belong to this group',
'escalate_to' => nil,
'unassigned_for' => nil,
'business_hour_id' => nil,
'group_type' => 'support_agent_group',
'created_at' => '2021-04-09T13:23:59Z',
'updated_at' => '2021-04-09T13:23:59Z'
},
{
'id' => 80_000_374_716,
'name' => 'Testing',
'description' => 'Members of the Testing team belong to this group',
'escalate_to' => nil,
'unassigned_for' => nil,
'business_hour_id' => nil,
'group_type' => 'support_agent_group',
'created_at' => '2021-04-09T13:23:59Z',
'updated_at' => '2021-04-09T13:23:59Z'
}
]
end
let(:process_payload) do
{
import_job: build_stubbed(:import_job, name: 'Import::Freshdesk', payload: {}),
dry_run: false,
object: 'Group',
request_params: {},
field_map: {},
id_map: {},
}
end
before do
# Mock the groups get request
stub_request(:get, 'https://yours.freshdesk.com/api/v2/groups?per_page=100').to_return(status: 200, body: JSON.generate(resources_payloud), headers: {})
end
it 'add groups' do
expect { process(process_payload) }.to change(Group, :count).by(2)
end
context 'when list request fails' do
before do
allow(Sequencer::Unit::Import::Freshdesk::Request).to receive(:handle_error).with(any_args).and_return(true)
stub_request(:get, 'https://yours.freshdesk.com/api/v2/groups?per_page=100').to_return(status: 400, headers: {})
end
it 'check that a failing response do not raise a hard error' do
expect { process(process_payload) }.to change(Group, :count).by(0)
end
end
end
end