cangaroo 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|