cangaroo 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +1 -1
- data/app/controllers/cangaroo/endpoint_controller.rb +22 -28
- data/app/interactors/cangaroo/count_json_object.rb +2 -12
- data/app/interactors/cangaroo/perform_jobs.rb +2 -6
- data/app/interactors/cangaroo/run_polls.rb +0 -1
- data/app/interactors/cangaroo/validate_json_schema.rb +3 -8
- data/app/jobs/cangaroo/base_job.rb +35 -0
- data/app/jobs/cangaroo/job.rb +2 -36
- data/app/jobs/cangaroo/poll_job.rb +20 -44
- data/app/jobs/cangaroo/push_job.rb +15 -0
- data/app/models/cangaroo/connection.rb +3 -3
- data/app/models/cangaroo/poll_timestamp.rb +1 -2
- data/db/migrate/20151028172151_create_cangaroo_connections.rb +1 -1
- data/db/migrate/20151030140821_add_parameters_to_cangaroo_connection.rb +1 -1
- data/db/migrate/20160317020230_create_cangaroo_poll_timestamps.rb +2 -2
- data/lib/cangaroo.rb +9 -0
- data/lib/cangaroo/class_configuration.rb +7 -4
- data/lib/cangaroo/engine.rb +2 -0
- data/lib/cangaroo/logger.rb +13 -58
- data/lib/cangaroo/logger_helper.rb +13 -0
- data/lib/cangaroo/migration.rb +11 -0
- data/lib/cangaroo/version.rb +1 -1
- data/lib/cangaroo/webhook/client.rb +27 -15
- data/spec/factories/cangaroo_connections.rb +26 -2
- data/spec/features/push_flow_spec.rb +79 -0
- data/spec/fixtures/json_payload_ok.json +3 -1
- data/spec/interactors/cangaroo/count_json_object_spec.rb +4 -2
- data/spec/interactors/cangaroo/perform_jobs_spec.rb +2 -3
- data/spec/jobs/cangaroo/poll_job_spec.rb +15 -17
- data/spec/jobs/cangaroo/{job_spec.rb → push_job_spec.rb} +25 -17
- data/spec/lib/cangaroo/logger_helper_spec.rb +21 -0
- data/spec/lib/cangaroo/logger_spec.rb +83 -0
- data/spec/lib/cangaroo/webhook/client_spec.rb +39 -24
- data/spec/rails_helper.rb +4 -2
- data/spec/{controllers/cangaroo/endpoint_controller_spec.rb → requests/cangaroo/endpoint_spec.rb} +21 -30
- data/spec/support/jobs/confirm_order_mail_job.rb +10 -0
- data/spec/support/jobs/erp_job.rb +10 -0
- data/spec/support/jobs/fake_push_job.rb +5 -0
- data/spec/support/jobs/shipped_order_mail_job.rb +10 -0
- data/spec/support/jobs/store_job.rb +10 -0
- data/spec/support/jobs/warehouse_job.rb +10 -0
- data/spec/support/rails_app.rb +1 -0
- data/spec/support/spec_helpers.rb +23 -0
- metadata +53 -32
- data/app/controllers/cangaroo/application_controller.rb +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3896bc0334e02871b872a34472b292f0d4400970
|
4
|
+
data.tar.gz: d489f9fbfda6a5597107eecc7c0df1eb8ba32d64
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: daab3c0a4a1a32e494f83bb2196e1037e9f223de107d810f546d224a8d2cff9b4d073c35282c82207f2d3e3b05ef4040ae094e082eaa74665ac0bbc077e2c829
|
7
|
+
data.tar.gz: a955392403bc2413366d76a7dd237cdfd009b75745dbbbe188a26de028ed8422b3f66cfbdf634aafa33badea145b4f1c4f392e7903d0a9041dabea123d3a5eaa
|
data/Rakefile
CHANGED
@@ -1,7 +1,5 @@
|
|
1
|
-
require_dependency 'cangaroo/application_controller'
|
2
|
-
|
3
1
|
module Cangaroo
|
4
|
-
class EndpointController <
|
2
|
+
class EndpointController < ActionController::Base
|
5
3
|
before_action :ensure_json_request
|
6
4
|
before_action :handle_request
|
7
5
|
|
@@ -19,51 +17,47 @@ module Cangaroo
|
|
19
17
|
private
|
20
18
|
|
21
19
|
def handle_error(exception)
|
22
|
-
if Rails.env.development?
|
23
|
-
|
24
|
-
else
|
25
|
-
render json: { error: 'Something went wrong!' }, status: 500
|
26
|
-
end
|
20
|
+
raise(exception) if Rails.env.development?
|
21
|
+
render json: { error: 'Something went wrong!' }, status: 500
|
27
22
|
end
|
28
23
|
|
29
24
|
def handle_request
|
30
25
|
@command = HandleRequest.call(
|
31
26
|
key: key,
|
32
27
|
token: token,
|
33
|
-
json_body:
|
28
|
+
json_body: JSON.parse(request.raw_post),
|
34
29
|
jobs: Rails.configuration.cangaroo.jobs
|
35
30
|
)
|
36
31
|
end
|
37
32
|
|
38
33
|
def ensure_json_request
|
39
34
|
return if request.headers['Content-Type'] == 'application/json'
|
35
|
+
|
40
36
|
render nothing: true, status: 406
|
41
37
|
end
|
42
38
|
|
43
39
|
def key
|
44
|
-
if Rails.configuration.cangaroo.basic_auth
|
45
|
-
|
46
|
-
return nil
|
47
|
-
end
|
48
|
-
|
49
|
-
user, pass = ActionController::HttpAuthentication::Basic::user_name_and_password(request)
|
50
|
-
user
|
51
|
-
else
|
52
|
-
request.headers['X-Hub-Store']
|
53
|
-
end
|
40
|
+
return user if Rails.configuration.cangaroo.basic_auth
|
41
|
+
request.headers['X-Hub-Store']
|
54
42
|
end
|
55
43
|
|
56
44
|
def token
|
57
|
-
if Rails.configuration.cangaroo.basic_auth
|
58
|
-
|
59
|
-
|
60
|
-
end
|
45
|
+
return password if Rails.configuration.cangaroo.basic_auth
|
46
|
+
request.headers['X-Hub-Access-Token']
|
47
|
+
end
|
61
48
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
49
|
+
def user
|
50
|
+
user_and_password.try(:first)
|
51
|
+
end
|
52
|
+
|
53
|
+
def password
|
54
|
+
user_and_password.try(:last)
|
55
|
+
end
|
56
|
+
|
57
|
+
def user_and_password
|
58
|
+
return nil unless ActionController::HttpAuthentication::Basic.has_basic_credentials?(request)
|
59
|
+
|
60
|
+
ActionController::HttpAuthentication::Basic.user_name_and_password(request)
|
67
61
|
end
|
68
62
|
end
|
69
63
|
end
|
@@ -1,23 +1,13 @@
|
|
1
1
|
module Cangaroo
|
2
2
|
class CountJsonObject
|
3
|
-
include Cangaroo::Log
|
4
3
|
include Interactor
|
5
4
|
|
6
|
-
before :prepare_context
|
7
|
-
|
8
5
|
def call
|
9
|
-
context.object_count = context.
|
6
|
+
context.object_count = context.json_body.each_with_object({}) do |(k, v), o|
|
10
7
|
o[k] = v.size
|
11
|
-
o
|
12
8
|
end
|
13
9
|
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
private
|
18
|
-
|
19
|
-
def prepare_context
|
20
|
-
context.data = JSON.parse(context.json_body)
|
10
|
+
Cangaroo.logger.info 'total consumed payloads', count: context.object_count
|
21
11
|
end
|
22
12
|
end
|
23
13
|
end
|
@@ -3,17 +3,13 @@ module Cangaroo
|
|
3
3
|
include Interactor
|
4
4
|
|
5
5
|
def call
|
6
|
-
|
6
|
+
context.json_body.each do |type, payloads|
|
7
7
|
payloads.each { |payload| enqueue_jobs(type, payload) }
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
11
|
private
|
12
12
|
|
13
|
-
def data
|
14
|
-
@data ||= JSON.parse(context.json_body)
|
15
|
-
end
|
16
|
-
|
17
13
|
def enqueue_jobs(type, payload)
|
18
14
|
initialize_jobs(type, payload).select(&:perform?).each(&:enqueue)
|
19
15
|
end
|
@@ -21,7 +17,7 @@ module Cangaroo
|
|
21
17
|
def initialize_jobs(type, payload)
|
22
18
|
context.jobs.map do |klass|
|
23
19
|
klass.new(
|
24
|
-
|
20
|
+
source_connection: context.source_connection,
|
25
21
|
type: type,
|
26
22
|
payload: payload
|
27
23
|
)
|
@@ -8,16 +8,11 @@ module Cangaroo
|
|
8
8
|
'minProperties': 1,
|
9
9
|
'additionalProperties': false,
|
10
10
|
'patternProperties': {
|
11
|
-
'^[a-z]*$': {
|
11
|
+
'^[a-z\-_]*$': {
|
12
12
|
'type': 'array',
|
13
13
|
'items': {
|
14
14
|
'type': 'object',
|
15
|
-
'required': ['id']
|
16
|
-
'properties': {
|
17
|
-
'id': {
|
18
|
-
'type': 'string'
|
19
|
-
}
|
20
|
-
}
|
15
|
+
'required': ['id']
|
21
16
|
}
|
22
17
|
}
|
23
18
|
}
|
@@ -26,7 +21,7 @@ module Cangaroo
|
|
26
21
|
before :prepare_context
|
27
22
|
|
28
23
|
def call
|
29
|
-
validation_response = JSON::Validator.fully_validate(SCHEMA, context.json_body)
|
24
|
+
validation_response = JSON::Validator.fully_validate(SCHEMA, context.json_body.to_json)
|
30
25
|
|
31
26
|
if validation_response.empty?
|
32
27
|
return true
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Cangaroo
|
2
|
+
class BaseJob < Job
|
3
|
+
include Cangaroo::ClassConfiguration
|
4
|
+
|
5
|
+
class_configuration :connection
|
6
|
+
class_configuration :path, ''
|
7
|
+
class_configuration :parameters, {}
|
8
|
+
class_configuration :process_response, true
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def connection_request
|
13
|
+
Cangaroo::Webhook::Client.new(destination_connection, path).post(transform, job_id, parameters)
|
14
|
+
end
|
15
|
+
|
16
|
+
def restart_flow(response)
|
17
|
+
# if no json was returned, the response should be discarded
|
18
|
+
return if response.blank?
|
19
|
+
|
20
|
+
return unless process_response
|
21
|
+
|
22
|
+
command = Cangaroo::PerformFlow.call(
|
23
|
+
source_connection: destination_connection,
|
24
|
+
json_body: response,
|
25
|
+
jobs: Rails.configuration.cangaroo.jobs.reject{ |job| job == self.class }
|
26
|
+
)
|
27
|
+
|
28
|
+
fail Cangaroo::Webhook::Error, command.message unless command.success?
|
29
|
+
end
|
30
|
+
|
31
|
+
def destination_connection
|
32
|
+
@destination_connection ||= Cangaroo::Connection.find_by!(name: connection)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/app/jobs/cangaroo/job.rb
CHANGED
@@ -1,45 +1,15 @@
|
|
1
1
|
module Cangaroo
|
2
2
|
class Job < ActiveJob::Base
|
3
|
-
include Cangaroo::
|
3
|
+
include Cangaroo::LoggerHelper
|
4
4
|
|
5
5
|
queue_as :cangaroo
|
6
6
|
|
7
|
-
class_configuration :connection
|
8
|
-
class_configuration :path, ''
|
9
|
-
class_configuration :parameters, {}
|
10
|
-
|
11
|
-
def perform(*)
|
12
|
-
restart_flow(connection_request)
|
13
|
-
end
|
14
|
-
|
15
7
|
def perform?
|
16
8
|
fail NotImplementedError
|
17
9
|
end
|
18
10
|
|
19
|
-
def transform
|
20
|
-
{ type.singularize => payload }
|
21
|
-
end
|
22
|
-
|
23
|
-
protected
|
24
|
-
|
25
|
-
def connection_request
|
26
|
-
Cangaroo::Webhook::Client.new(destination_connection, path)
|
27
|
-
.post(transform, @job_id, parameters)
|
28
|
-
end
|
29
|
-
|
30
|
-
def restart_flow(response)
|
31
|
-
# if no json was returned, the response should be discarded
|
32
|
-
return if response.blank?
|
33
|
-
|
34
|
-
PerformFlow.call(
|
35
|
-
source_connection: destination_connection,
|
36
|
-
json_body: response.to_json,
|
37
|
-
jobs: Rails.configuration.cangaroo.jobs
|
38
|
-
)
|
39
|
-
end
|
40
|
-
|
41
11
|
def source_connection
|
42
|
-
arguments.first.fetch(:
|
12
|
+
arguments.first.fetch(:source_connection)
|
43
13
|
end
|
44
14
|
|
45
15
|
def type
|
@@ -49,9 +19,5 @@ module Cangaroo
|
|
49
19
|
def payload
|
50
20
|
arguments.first.fetch(:payload)
|
51
21
|
end
|
52
|
-
|
53
|
-
def destination_connection
|
54
|
-
@connection ||= Cangaroo::Connection.find_by!(name: connection)
|
55
|
-
end
|
56
22
|
end
|
57
23
|
end
|
@@ -1,67 +1,43 @@
|
|
1
1
|
module Cangaroo
|
2
|
-
class PollJob <
|
3
|
-
|
4
|
-
include Cangaroo::ClassConfiguration
|
2
|
+
class PollJob < BaseJob
|
3
|
+
class_configuration :frequency, 1.day
|
5
4
|
|
6
|
-
|
5
|
+
attr_reader :current_time
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
class_configuration :parameters, {}
|
7
|
+
def transform
|
8
|
+
{ last_poll: last_poll_timestamp.to_i }
|
9
|
+
end
|
12
10
|
|
13
11
|
def perform(*)
|
14
|
-
|
15
|
-
|
16
|
-
last_poll = Time.at(arguments.first.fetch(:last_poll)).to_datetime
|
17
|
-
current_time = DateTime.now
|
12
|
+
@current_time = DateTime.now
|
18
13
|
|
19
14
|
if !perform?(current_time)
|
20
|
-
|
15
|
+
Cangaroo.logger.info 'skipping poll', job_tags
|
21
16
|
return
|
22
17
|
end
|
23
18
|
|
24
|
-
|
25
|
-
|
26
|
-
response = Cangaroo::Webhook::Client.new(destination_connection, path)
|
27
|
-
.post({ last_poll: last_poll_timestamp.to_i }, @job_id, parameters)
|
28
|
-
|
29
|
-
log.info 'processing poll results'
|
19
|
+
restart_flow(connection_request)
|
30
20
|
|
31
|
-
|
32
|
-
key: destination_connection.key,
|
33
|
-
token: destination_connection.token,
|
34
|
-
json_body: response.to_json,
|
35
|
-
jobs: Rails.configuration.cangaroo.jobs
|
36
|
-
)
|
37
|
-
|
38
|
-
if !command.success?
|
39
|
-
fail Cangaroo::Webhook::Error, command.message
|
40
|
-
end
|
41
|
-
|
42
|
-
log.info 'updating last poll', last_poll: current_time
|
43
|
-
|
44
|
-
last_job_poll = Cangaroo::PollTimestamp.for_class(self.class)
|
45
|
-
last_job_poll.value = current_time
|
46
|
-
last_job_poll.save!
|
47
|
-
|
48
|
-
log.reset_context!
|
21
|
+
update_last_poll_timestamp
|
49
22
|
end
|
50
23
|
|
51
24
|
def perform?(execution_time)
|
52
25
|
last_poll_timestamp.nil? ||
|
53
|
-
|
26
|
+
execution_time.to_i - last_poll_timestamp.to_i > self.class.frequency
|
54
27
|
end
|
55
28
|
|
56
29
|
protected
|
57
30
|
|
58
|
-
|
59
|
-
|
60
|
-
end
|
31
|
+
def update_last_poll_timestamp
|
32
|
+
Cangaroo.logger.info 'updating last poll', job_tags(last_poll: current_time)
|
61
33
|
|
62
|
-
|
63
|
-
|
64
|
-
|
34
|
+
last_job_poll = Cangaroo::PollTimestamp.for_class(self.class)
|
35
|
+
last_job_poll.value = current_time
|
36
|
+
last_job_poll.save!
|
37
|
+
end
|
65
38
|
|
39
|
+
def last_poll_timestamp
|
40
|
+
@last_poll_timestamp ||= Cangaroo::PollTimestamp.for_class(self.class).value
|
41
|
+
end
|
66
42
|
end
|
67
43
|
end
|
@@ -7,11 +7,10 @@ module Cangaroo
|
|
7
7
|
validates_uniqueness_of :job, scope: :connection
|
8
8
|
|
9
9
|
def self.for_class(klass)
|
10
|
-
|
10
|
+
where(
|
11
11
|
job: klass.to_s,
|
12
12
|
connection: Cangaroo::Connection.find_by!(name: klass.connection)
|
13
13
|
).first_or_initialize
|
14
14
|
end
|
15
|
-
|
16
15
|
end
|
17
16
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class CreateCangarooPollTimestamps <
|
1
|
+
class CreateCangarooPollTimestamps < Cangaroo::Migration[4.2]
|
2
2
|
def change
|
3
3
|
create_table :cangaroo_poll_timestamps do |t|
|
4
4
|
t.string :job
|
@@ -7,6 +7,6 @@ class CreateCangarooPollTimestamps < ActiveRecord::Migration
|
|
7
7
|
t.timestamps
|
8
8
|
end
|
9
9
|
|
10
|
-
add_index :cangaroo_poll_timestamps, [:job], :
|
10
|
+
add_index :cangaroo_poll_timestamps, [:job], name: 'index_cangaroo_poll_timestamps_on_job'
|
11
11
|
end
|
12
12
|
end
|