cangaroo 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +32 -0
- data/app/controllers/cangaroo/application_controller.rb +4 -0
- data/app/controllers/cangaroo/endpoint_controller.rb +49 -0
- data/app/interactors/cangaroo/authenticate_connection.rb +19 -0
- data/app/interactors/cangaroo/count_json_object.rb +20 -0
- data/app/interactors/cangaroo/handle_request.rb +10 -0
- data/app/interactors/cangaroo/perform_jobs.rb +31 -0
- data/app/interactors/cangaroo/validate_json_schema.rb +31 -0
- data/app/jobs/cangaroo/job.rb +63 -0
- data/app/models/cangaroo/connection.rb +12 -0
- data/config/routes.rb +3 -0
- data/db/migrate/20151028172151_create_cangaroo_connections.rb +12 -0
- data/db/migrate/20151030140821_add_parameters_to_cangaroo_connection.rb +5 -0
- data/lib/cangaroo.rb +10 -0
- data/lib/cangaroo/engine.rb +17 -0
- data/lib/cangaroo/version.rb +3 -0
- data/lib/cangaroo/webhook/client.rb +44 -0
- data/lib/cangaroo/webhook/error.rb +6 -0
- data/lib/tasks/cangaroo_tasks.rake +4 -0
- data/spec/controllers/cangaroo/endpoint_controller_spec.rb +72 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +29 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +31 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +11 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +41 -0
- data/spec/dummy/config/environments/production.rb +79 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +9 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +4 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/schema.rb +29 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/cangaroo.log +0 -0
- data/spec/dummy/log/development.log +3466 -0
- data/spec/dummy/log/test.log +139640 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/factories/cangaroo_connections.rb +9 -0
- data/spec/fixtures/json_payload_no_id.json +21 -0
- data/spec/fixtures/json_payload_ok.json +22 -0
- data/spec/fixtures/json_payload_wrong_key.json +22 -0
- data/spec/interactors/cangaroo/authenticate_connection_spec.rb +46 -0
- data/spec/interactors/cangaroo/count_json_object_spec.rb +17 -0
- data/spec/interactors/cangaroo/handle_request_spec.rb +18 -0
- data/spec/interactors/cangaroo/perform_jobs_spec.rb +42 -0
- data/spec/interactors/cangaroo/validate_json_schema_spec.rb +51 -0
- data/spec/jobs/cangaroo/job_spec.rb +55 -0
- data/spec/lib/cangaroo/webhook/client_spec.rb +69 -0
- data/spec/models/cangaroo/connection_spec.rb +15 -0
- data/spec/rails_helper.rb +85 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/support/spec_helpers.rb +11 -0
- metadata +345 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The page you were looking for doesn't exist (404)</title>
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
6
|
+
<style>
|
7
|
+
body {
|
8
|
+
background-color: #EFEFEF;
|
9
|
+
color: #2E2F30;
|
10
|
+
text-align: center;
|
11
|
+
font-family: arial, sans-serif;
|
12
|
+
margin: 0;
|
13
|
+
}
|
14
|
+
|
15
|
+
div.dialog {
|
16
|
+
width: 95%;
|
17
|
+
max-width: 33em;
|
18
|
+
margin: 4em auto 0;
|
19
|
+
}
|
20
|
+
|
21
|
+
div.dialog > div {
|
22
|
+
border: 1px solid #CCC;
|
23
|
+
border-right-color: #999;
|
24
|
+
border-left-color: #999;
|
25
|
+
border-bottom-color: #BBB;
|
26
|
+
border-top: #B00100 solid 4px;
|
27
|
+
border-top-left-radius: 9px;
|
28
|
+
border-top-right-radius: 9px;
|
29
|
+
background-color: white;
|
30
|
+
padding: 7px 12% 0;
|
31
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
32
|
+
}
|
33
|
+
|
34
|
+
h1 {
|
35
|
+
font-size: 100%;
|
36
|
+
color: #730E15;
|
37
|
+
line-height: 1.5em;
|
38
|
+
}
|
39
|
+
|
40
|
+
div.dialog > p {
|
41
|
+
margin: 0 0 1em;
|
42
|
+
padding: 1em;
|
43
|
+
background-color: #F7F7F7;
|
44
|
+
border: 1px solid #CCC;
|
45
|
+
border-right-color: #999;
|
46
|
+
border-left-color: #999;
|
47
|
+
border-bottom-color: #999;
|
48
|
+
border-bottom-left-radius: 4px;
|
49
|
+
border-bottom-right-radius: 4px;
|
50
|
+
border-top-color: #DADADA;
|
51
|
+
color: #666;
|
52
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
53
|
+
}
|
54
|
+
</style>
|
55
|
+
</head>
|
56
|
+
|
57
|
+
<body>
|
58
|
+
<!-- This file lives in public/404.html -->
|
59
|
+
<div class="dialog">
|
60
|
+
<div>
|
61
|
+
<h1>The page you were looking for doesn't exist.</h1>
|
62
|
+
<p>You may have mistyped the address or the page may have moved.</p>
|
63
|
+
</div>
|
64
|
+
<p>If you are the application owner check the logs for more information.</p>
|
65
|
+
</div>
|
66
|
+
</body>
|
67
|
+
</html>
|
@@ -0,0 +1,67 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>The change you wanted was rejected (422)</title>
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
6
|
+
<style>
|
7
|
+
body {
|
8
|
+
background-color: #EFEFEF;
|
9
|
+
color: #2E2F30;
|
10
|
+
text-align: center;
|
11
|
+
font-family: arial, sans-serif;
|
12
|
+
margin: 0;
|
13
|
+
}
|
14
|
+
|
15
|
+
div.dialog {
|
16
|
+
width: 95%;
|
17
|
+
max-width: 33em;
|
18
|
+
margin: 4em auto 0;
|
19
|
+
}
|
20
|
+
|
21
|
+
div.dialog > div {
|
22
|
+
border: 1px solid #CCC;
|
23
|
+
border-right-color: #999;
|
24
|
+
border-left-color: #999;
|
25
|
+
border-bottom-color: #BBB;
|
26
|
+
border-top: #B00100 solid 4px;
|
27
|
+
border-top-left-radius: 9px;
|
28
|
+
border-top-right-radius: 9px;
|
29
|
+
background-color: white;
|
30
|
+
padding: 7px 12% 0;
|
31
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
32
|
+
}
|
33
|
+
|
34
|
+
h1 {
|
35
|
+
font-size: 100%;
|
36
|
+
color: #730E15;
|
37
|
+
line-height: 1.5em;
|
38
|
+
}
|
39
|
+
|
40
|
+
div.dialog > p {
|
41
|
+
margin: 0 0 1em;
|
42
|
+
padding: 1em;
|
43
|
+
background-color: #F7F7F7;
|
44
|
+
border: 1px solid #CCC;
|
45
|
+
border-right-color: #999;
|
46
|
+
border-left-color: #999;
|
47
|
+
border-bottom-color: #999;
|
48
|
+
border-bottom-left-radius: 4px;
|
49
|
+
border-bottom-right-radius: 4px;
|
50
|
+
border-top-color: #DADADA;
|
51
|
+
color: #666;
|
52
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
53
|
+
}
|
54
|
+
</style>
|
55
|
+
</head>
|
56
|
+
|
57
|
+
<body>
|
58
|
+
<!-- This file lives in public/422.html -->
|
59
|
+
<div class="dialog">
|
60
|
+
<div>
|
61
|
+
<h1>The change you wanted was rejected.</h1>
|
62
|
+
<p>Maybe you tried to change something you didn't have access to.</p>
|
63
|
+
</div>
|
64
|
+
<p>If you are the application owner check the logs for more information.</p>
|
65
|
+
</div>
|
66
|
+
</body>
|
67
|
+
</html>
|
@@ -0,0 +1,66 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>We're sorry, but something went wrong (500)</title>
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
6
|
+
<style>
|
7
|
+
body {
|
8
|
+
background-color: #EFEFEF;
|
9
|
+
color: #2E2F30;
|
10
|
+
text-align: center;
|
11
|
+
font-family: arial, sans-serif;
|
12
|
+
margin: 0;
|
13
|
+
}
|
14
|
+
|
15
|
+
div.dialog {
|
16
|
+
width: 95%;
|
17
|
+
max-width: 33em;
|
18
|
+
margin: 4em auto 0;
|
19
|
+
}
|
20
|
+
|
21
|
+
div.dialog > div {
|
22
|
+
border: 1px solid #CCC;
|
23
|
+
border-right-color: #999;
|
24
|
+
border-left-color: #999;
|
25
|
+
border-bottom-color: #BBB;
|
26
|
+
border-top: #B00100 solid 4px;
|
27
|
+
border-top-left-radius: 9px;
|
28
|
+
border-top-right-radius: 9px;
|
29
|
+
background-color: white;
|
30
|
+
padding: 7px 12% 0;
|
31
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
32
|
+
}
|
33
|
+
|
34
|
+
h1 {
|
35
|
+
font-size: 100%;
|
36
|
+
color: #730E15;
|
37
|
+
line-height: 1.5em;
|
38
|
+
}
|
39
|
+
|
40
|
+
div.dialog > p {
|
41
|
+
margin: 0 0 1em;
|
42
|
+
padding: 1em;
|
43
|
+
background-color: #F7F7F7;
|
44
|
+
border: 1px solid #CCC;
|
45
|
+
border-right-color: #999;
|
46
|
+
border-left-color: #999;
|
47
|
+
border-bottom-color: #999;
|
48
|
+
border-bottom-left-radius: 4px;
|
49
|
+
border-bottom-right-radius: 4px;
|
50
|
+
border-top-color: #DADADA;
|
51
|
+
color: #666;
|
52
|
+
box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
|
53
|
+
}
|
54
|
+
</style>
|
55
|
+
</head>
|
56
|
+
|
57
|
+
<body>
|
58
|
+
<!-- This file lives in public/500.html -->
|
59
|
+
<div class="dialog">
|
60
|
+
<div>
|
61
|
+
<h1>We're sorry, but something went wrong.</h1>
|
62
|
+
</div>
|
63
|
+
<p>If you are the application owner check the logs for more information.</p>
|
64
|
+
</div>
|
65
|
+
</body>
|
66
|
+
</html>
|
File without changes
|
@@ -0,0 +1,9 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
factory :cangaroo_connection, class: 'Cangaroo::Connection' do
|
3
|
+
name :store
|
4
|
+
url 'www.store.com'
|
5
|
+
parameters { { first: 'first', second: 'second' } }
|
6
|
+
key '1e4e888ac66f8dd41e00c5a7ac36a32a9950d271'
|
7
|
+
token '8d49cddb4291562808bfca1bee8a9f7cf947a987'
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
{
|
2
|
+
"orders":[
|
3
|
+
{
|
4
|
+
"id":"O154085346172",
|
5
|
+
"state":"cart"
|
6
|
+
},
|
7
|
+
{
|
8
|
+
"id":"O154085343224",
|
9
|
+
"state":"payed"
|
10
|
+
}
|
11
|
+
],
|
12
|
+
"shipments":[
|
13
|
+
{
|
14
|
+
"id":"S53454325",
|
15
|
+
"state":"shipped"
|
16
|
+
},
|
17
|
+
{
|
18
|
+
"id":"S53565543",
|
19
|
+
"state":"waiting"
|
20
|
+
}
|
21
|
+
]
|
22
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
{
|
2
|
+
"Wrong Key":[
|
3
|
+
{
|
4
|
+
"id":"O154085346172",
|
5
|
+
"state":"cart"
|
6
|
+
},
|
7
|
+
{
|
8
|
+
"id":"O154085343224",
|
9
|
+
"state":"payed"
|
10
|
+
}
|
11
|
+
],
|
12
|
+
"shipments":[
|
13
|
+
{
|
14
|
+
"id":"S53454325",
|
15
|
+
"state":"shipped"
|
16
|
+
},
|
17
|
+
{
|
18
|
+
"id":"S53565543",
|
19
|
+
"state":"waiting"
|
20
|
+
}
|
21
|
+
]
|
22
|
+
}
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe Cangaroo::AuthenticateConnection do
|
4
|
+
subject(:context) do
|
5
|
+
Cangaroo::AuthenticateConnection.call(key: 'connection_key',
|
6
|
+
token: 'secret_token')
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '.call' do
|
10
|
+
context 'when given valid credentials' do
|
11
|
+
let(:connection) { double(:connection) }
|
12
|
+
|
13
|
+
before do
|
14
|
+
allow(Cangaroo::Connection).to receive(:authenticate)
|
15
|
+
.with('connection_key', 'secret_token').and_return(connection)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'succeeds' do
|
19
|
+
expect(context).to be_a_success
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'provides the connection' do
|
23
|
+
expect(context.source_connection).to eq(connection)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'when given invalid credentials' do
|
28
|
+
before do
|
29
|
+
allow(Cangaroo::Connection).to receive(:authenticate)
|
30
|
+
.with('connection_key', 'secret_token').and_return(nil)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'fails' do
|
34
|
+
expect(context).to be_a_failure
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'provides a failure message' do
|
38
|
+
expect(context.message).to be_present
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'provides a failure error code' do
|
42
|
+
expect(context.error_code).to eq 401
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe Cangaroo::CountJsonObject do
|
4
|
+
subject(:context) { Cangaroo::CountJsonObject.call(json_body: json_body) }
|
5
|
+
|
6
|
+
let(:json_body) { load_fixture('json_payload_ok.json') }
|
7
|
+
|
8
|
+
describe '.call' do
|
9
|
+
it 'provides the object_count' do
|
10
|
+
expect(context.object_count).to eq('orders' => 2, 'shipments' => 2)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'succeeds' do
|
14
|
+
expect(context).to be_a_success
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe Cangaroo::HandleRequest do
|
4
|
+
subject { described_class.new }
|
5
|
+
|
6
|
+
context 'organizes interactors' do
|
7
|
+
subject { described_class.organized }
|
8
|
+
|
9
|
+
let(:interactors) do
|
10
|
+
[Cangaroo::AuthenticateConnection,
|
11
|
+
Cangaroo::ValidateJsonSchema,
|
12
|
+
Cangaroo::CountJsonObject,
|
13
|
+
Cangaroo::PerformJobs]
|
14
|
+
end
|
15
|
+
|
16
|
+
it { is_expected.to eql interactors }
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
class JobA < Cangaroo::Job; end
|
4
|
+
class JobB < Cangaroo::Job; end
|
5
|
+
|
6
|
+
describe Cangaroo::PerformJobs do
|
7
|
+
subject(:context) do
|
8
|
+
Cangaroo::PerformJobs.call(json_body: json_body,
|
9
|
+
jobs: [JobA, JobB],
|
10
|
+
source_connection: connection)
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:connection) { create(:cangaroo_connection) }
|
14
|
+
|
15
|
+
before do
|
16
|
+
allow(JobA).to receive(:new).with(any_args).and_return(job_a)
|
17
|
+
allow(JobB).to receive(:new).with(any_args).and_return(job_b)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '.call' do
|
21
|
+
let(:json_body) { load_fixture('json_payload_ok.json') }
|
22
|
+
|
23
|
+
let(:job_a) { double('job_a', perform?: true, enqueue: nil) }
|
24
|
+
let(:job_b) { double('job_b', perform?: false, enqueue: nil) }
|
25
|
+
|
26
|
+
it 'instantiates jobs' do
|
27
|
+
context
|
28
|
+
expect(JobA).to have_received(:new).exactly(4).times
|
29
|
+
expect(JobB).to have_received(:new).exactly(4).times
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'enqueues only cangaroo jobs that can perform' do
|
33
|
+
context
|
34
|
+
expect(job_a).to have_received(:enqueue).exactly(4).times
|
35
|
+
expect(job_b).to_not have_received(:enqueue)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'succeeds' do
|
39
|
+
expect(context).to be_a_success
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
describe Cangaroo::ValidateJsonSchema do
|
4
|
+
subject(:context) { Cangaroo::ValidateJsonSchema.call(json_body: json_body) }
|
5
|
+
|
6
|
+
describe '.call' do
|
7
|
+
context 'when json is well formatted' do
|
8
|
+
let(:json_body) { JSON.parse(load_fixture('json_payload_ok.json')) }
|
9
|
+
|
10
|
+
it 'succeeds' do
|
11
|
+
expect(context).to be_a_success
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when json is not well formatted' do
|
16
|
+
describe 'with wrong main key' do
|
17
|
+
let(:json_body) do
|
18
|
+
JSON.parse(load_fixture('json_payload_wrong_key.json'))
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'fails' do
|
22
|
+
expect(context).to be_a_failure
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'provides a failure message' do
|
26
|
+
expect(context.message).to be_present
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'provides a failure error code' do
|
30
|
+
expect(context.error_code).to eq 500
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'without an object id' do
|
35
|
+
let(:json_body) { JSON.parse(load_fixture('json_payload_no_id.json')) }
|
36
|
+
|
37
|
+
it 'fails' do
|
38
|
+
expect(context).to be_a_failure
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'provides a failure message' do
|
42
|
+
expect(context.message).to be_present
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'provides a failure error code' do
|
46
|
+
expect(context.error_code).to eq 500
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|