contextio 0.5.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +4 -0
- data/.gitignore +8 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +5 -0
- data/Gemfile +3 -0
- data/LICENSE.md +20 -0
- data/README.md +62 -22
- data/Rakefile +46 -36
- data/contextio.gemspec +30 -0
- data/lib/contextio.rb +69 -583
- data/lib/contextio/account.rb +132 -0
- data/lib/contextio/account_collection.rb +57 -0
- data/lib/contextio/account_sync_data.rb +22 -0
- data/lib/contextio/api.rb +162 -0
- data/lib/contextio/api/association_helpers.rb +17 -0
- data/lib/contextio/api/resource.rb +230 -0
- data/lib/contextio/api/resource_collection.rb +174 -0
- data/lib/contextio/api/url_builder.rb +153 -0
- data/lib/contextio/body_part.rb +45 -0
- data/lib/contextio/body_part_collection.rb +13 -0
- data/lib/contextio/connect_token.rb +57 -0
- data/lib/contextio/connect_token_collection.rb +44 -0
- data/lib/contextio/contact.rb +43 -0
- data/lib/contextio/contact_collection.rb +21 -0
- data/lib/contextio/email_address.rb +53 -0
- data/lib/contextio/email_address_collection.rb +21 -0
- data/lib/contextio/email_settings.rb +146 -0
- data/lib/contextio/file.rb +92 -0
- data/lib/contextio/file_collection.rb +13 -0
- data/lib/contextio/folder.rb +56 -0
- data/lib/contextio/folder_collection.rb +18 -0
- data/lib/contextio/folder_sync_data.rb +32 -0
- data/lib/contextio/message.rb +96 -0
- data/lib/contextio/message_collection.rb +35 -0
- data/lib/contextio/oauth_provider.rb +29 -0
- data/lib/contextio/oauth_provider_collection.rb +46 -0
- data/lib/contextio/source.rb +55 -0
- data/lib/contextio/source_collection.rb +41 -0
- data/lib/contextio/source_sync_data.rb +23 -0
- data/lib/contextio/thread.rb +15 -0
- data/lib/contextio/thread_collection.rb +25 -0
- data/lib/contextio/version.rb +11 -0
- data/lib/contextio/webhook.rb +39 -0
- data/lib/contextio/webhook_collection.rb +26 -0
- data/spec/config.yml.example +3 -0
- data/spec/contextio/account_collection_spec.rb +78 -0
- data/spec/contextio/account_spec.rb +52 -0
- data/spec/contextio/api/association_helpers_spec.rb +28 -0
- data/spec/contextio/api/resource_collection_spec.rb +286 -0
- data/spec/contextio/api/resource_spec.rb +467 -0
- data/spec/contextio/api/url_builder_spec.rb +78 -0
- data/spec/contextio/api_spec.rb +123 -0
- data/spec/contextio/connect_token_collection_spec.rb +74 -0
- data/spec/contextio/connect_token_spec.rb +58 -0
- data/spec/contextio/email_settings_spec.rb +112 -0
- data/spec/contextio/oauth_provider_collection_spec.rb +36 -0
- data/spec/contextio/oauth_provider_spec.rb +120 -0
- data/spec/contextio/source_collection_spec.rb +57 -0
- data/spec/contextio/source_spec.rb +52 -0
- data/spec/contextio/version_spec.rb +10 -0
- data/spec/contextio_spec.rb +64 -0
- data/spec/spec_helper.rb +17 -0
- metadata +234 -12
- data/README.textile +0 -29
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'contextio/api/url_builder'
|
3
|
+
|
4
|
+
describe ContextIO::API::URLBuilder do
|
5
|
+
let(:api) { double('api') }
|
6
|
+
|
7
|
+
describe "#url_for" do
|
8
|
+
subject { ContextIO::API::URLBuilder.url_for(resource) }
|
9
|
+
|
10
|
+
context "when passed an unregistered class" do
|
11
|
+
let(:resource) { "String isn't registered."}
|
12
|
+
|
13
|
+
it "raises an exception" do
|
14
|
+
expect { subject }.to raise_exception(ContextIO::API::URLBuilder::Error)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when passed a ConnectToken" do
|
19
|
+
context "with an account" do
|
20
|
+
let(:account) { double('account', id: 'account_id') }
|
21
|
+
let(:resource) { ContextIO::ConnectToken.new(api, token: 'token', account: account) }
|
22
|
+
|
23
|
+
it { should eq('accounts/account_id/connect_tokens/token') }
|
24
|
+
end
|
25
|
+
|
26
|
+
context "without an account" do
|
27
|
+
let(:resource) { ContextIO::ConnectToken.new(api, token: 'token', api_attributes: { 'account' => { } }) }
|
28
|
+
|
29
|
+
it { should eq('connect_tokens/token') }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "when passed a ConnectTokenCollection" do
|
34
|
+
context "with an account" do
|
35
|
+
let(:account) { double('account', id: 'account_id') }
|
36
|
+
let(:resource) { ContextIO::ConnectTokenCollection.new(api, account: account) }
|
37
|
+
|
38
|
+
it { should eq('accounts/account_id/connect_tokens') }
|
39
|
+
end
|
40
|
+
|
41
|
+
context "wiehout an account" do
|
42
|
+
let(:resource) { ContextIO::ConnectTokenCollection.new(api) }
|
43
|
+
|
44
|
+
it { should eq('connect_tokens') }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when passed an OAuthProvider" do
|
49
|
+
let(:resource) { ContextIO::OAuthProvider.new(api, provider_consumer_key: 'provider_consumer_key') }
|
50
|
+
|
51
|
+
it { should eq('oauth_providers/provider_consumer_key') }
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when passed an OAuthProviderCollection" do
|
55
|
+
let(:resource) { ContextIO::OAuthProviderCollection.new(api) }
|
56
|
+
|
57
|
+
it { should eq('oauth_providers') }
|
58
|
+
end
|
59
|
+
|
60
|
+
context "when passed an EmailSettings" do
|
61
|
+
let(:resource) { ContextIO::EmailSettings.new(api, 'email') }
|
62
|
+
|
63
|
+
it { should eq('discovery') }
|
64
|
+
end
|
65
|
+
|
66
|
+
context "when passed an Account" do
|
67
|
+
let(:resource) { ContextIO::Account.new(api, id: 'account_id') }
|
68
|
+
|
69
|
+
it { should eq('accounts/account_id') }
|
70
|
+
end
|
71
|
+
|
72
|
+
context "when passed an AccountCollection" do
|
73
|
+
let(:resource) { ContextIO::AccountCollection.new(api) }
|
74
|
+
|
75
|
+
it { should eq('accounts') }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'contextio/api'
|
3
|
+
|
4
|
+
describe ContextIO::API do
|
5
|
+
describe ".version" do
|
6
|
+
subject { ContextIO::API }
|
7
|
+
|
8
|
+
it "uses API version 2.0" do
|
9
|
+
expect(subject.version).to eq('2.0')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe ".base_url" do
|
14
|
+
subject { ContextIO::API }
|
15
|
+
|
16
|
+
it "is https://api.context.io" do
|
17
|
+
expect(subject.base_url).to eq('https://api.context.io')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe ".new" do
|
22
|
+
subject { ContextIO::API.new('test_key', 'test_secret') }
|
23
|
+
|
24
|
+
it "takes a key" do
|
25
|
+
expect(subject.key).to eq('test_key')
|
26
|
+
end
|
27
|
+
|
28
|
+
it "takes a secret" do
|
29
|
+
expect(subject.secret).to eq('test_secret')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#path" do
|
34
|
+
context "without params" do
|
35
|
+
subject { ContextIO::API.new(nil, nil).path('test_command') }
|
36
|
+
|
37
|
+
it "puts the command in the path" do
|
38
|
+
expect(subject).to eq('/2.0/test_command')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "with params" do
|
43
|
+
subject { ContextIO::API.new(nil, nil).path('test_command', foo: 1, bar: %w(a b c)) }
|
44
|
+
|
45
|
+
it "URL encodes the params" do
|
46
|
+
expect(subject).to eq('/2.0/test_command?foo=1&bar=a%2Cb%2Cc')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "with a full URL" do
|
51
|
+
subject { ContextIO::API.new(nil, nil).path('https://api.context.io/2.0/test_command') }
|
52
|
+
|
53
|
+
it "strips out the command" do
|
54
|
+
expect(subject).to eq('/2.0/test_command')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#request" do
|
60
|
+
subject { ContextIO::API.new(nil, nil).request(:get, 'test') }
|
61
|
+
|
62
|
+
context "with a good response" do
|
63
|
+
before do
|
64
|
+
FakeWeb.register_uri(
|
65
|
+
:get,
|
66
|
+
'https://api.context.io/2.0/test',
|
67
|
+
body: JSON.dump('a' => 'b', 'c' => 'd')
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "parses the JSON response" do
|
72
|
+
expect(subject).to eq('a' => 'b', 'c' => 'd')
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "with a bad response that has a body" do
|
77
|
+
before do
|
78
|
+
FakeWeb.register_uri(
|
79
|
+
:get,
|
80
|
+
'https://api.context.io/2.0/test',
|
81
|
+
status: ['400', 'Bad Request'],
|
82
|
+
body: JSON.dump('type' => 'error', 'value' => 'nope')
|
83
|
+
)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "raises an API error with the body message" do
|
87
|
+
expect { subject }.to raise_error(ContextIO::API::Error, 'nope')
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "with a bad response that has no body" do
|
92
|
+
before do
|
93
|
+
FakeWeb.register_uri(
|
94
|
+
:get,
|
95
|
+
'https://api.context.io/2.0/test',
|
96
|
+
status: ['400', 'Bad Request']
|
97
|
+
)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "raises an API error with the header message" do
|
101
|
+
expect { subject }.to raise_error(ContextIO::API::Error, 'Bad Request')
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe ".url_for" do
|
107
|
+
it "delegates to ContextIO::API::URLBuilder" do
|
108
|
+
ContextIO::API::URLBuilder.should_receive(:url_for).with('foo')
|
109
|
+
|
110
|
+
ContextIO::API.url_for('foo')
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "#url_for" do
|
115
|
+
subject { ContextIO::API.new('test_key', 'test_secret') }
|
116
|
+
|
117
|
+
it "delegates to the class" do
|
118
|
+
ContextIO::API.should_receive(:url_for).with('foo')
|
119
|
+
|
120
|
+
subject.url_for('foo')
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'contextio/connect_token_collection'
|
3
|
+
|
4
|
+
describe ContextIO::ConnectTokenCollection do
|
5
|
+
let(:api) { double('API', url_for: 'url from api') }
|
6
|
+
|
7
|
+
subject { ContextIO::ConnectTokenCollection.new(api) }
|
8
|
+
|
9
|
+
describe "#create" do
|
10
|
+
before do
|
11
|
+
api.stub(:request).with(:post, anything, anything).and_return({ token: '1234' })
|
12
|
+
end
|
13
|
+
|
14
|
+
it "posts to the api" do
|
15
|
+
api.should_receive(:request).with(
|
16
|
+
:post,
|
17
|
+
'url from api',
|
18
|
+
hash_including(callback_url: 'http://callback.com')
|
19
|
+
)
|
20
|
+
|
21
|
+
subject.create('http://callback.com')
|
22
|
+
end
|
23
|
+
|
24
|
+
it "doesn't make any more API calls than it needs to" do
|
25
|
+
api.should_not_receive(:request).with(:get, anything, anything)
|
26
|
+
|
27
|
+
subject.create('http://callback.com')
|
28
|
+
end
|
29
|
+
|
30
|
+
it "returns a ConnectToken" do
|
31
|
+
expect(subject.create('http://callback.com')).to be_a(ContextIO::ConnectToken)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "takes an optional service level" do
|
35
|
+
api.should_receive(:request).with(
|
36
|
+
anything,
|
37
|
+
anything,
|
38
|
+
hash_including(service_level: 'PRO')
|
39
|
+
)
|
40
|
+
|
41
|
+
subject.create('http://callback.com', service_level: 'PRO')
|
42
|
+
end
|
43
|
+
|
44
|
+
it "takes an optional email" do
|
45
|
+
api.should_receive(:request).with(
|
46
|
+
anything,
|
47
|
+
anything,
|
48
|
+
hash_including(email: 'person@email.com')
|
49
|
+
)
|
50
|
+
|
51
|
+
subject.create('http://callback.com', email: 'person@email.com')
|
52
|
+
end
|
53
|
+
|
54
|
+
it "takes an optional first name" do
|
55
|
+
api.should_receive(:request).with(
|
56
|
+
anything,
|
57
|
+
anything,
|
58
|
+
hash_including(first_name: 'Bruno')
|
59
|
+
)
|
60
|
+
|
61
|
+
subject.create('http://callback.com', first_name: 'Bruno')
|
62
|
+
end
|
63
|
+
|
64
|
+
it "takes an optional last name" do
|
65
|
+
api.should_receive(:request).with(
|
66
|
+
anything,
|
67
|
+
anything,
|
68
|
+
hash_including(last_name: 'Morency')
|
69
|
+
)
|
70
|
+
|
71
|
+
subject.create('http://callback.com', last_name: 'Morency')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'contextio/connect_token'
|
3
|
+
|
4
|
+
describe ContextIO::ConnectToken do
|
5
|
+
let(:api) { double('API') }
|
6
|
+
|
7
|
+
describe ".new" do
|
8
|
+
subject { ContextIO::ConnectToken.new(api, token: '1234', foo: 'bar') }
|
9
|
+
|
10
|
+
it "takes an api handle" do
|
11
|
+
expect(subject.api).to eq(api)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "assigns instance variables for hash arguments" do
|
15
|
+
expect(subject.instance_variable_get('@token')).to eq('1234')
|
16
|
+
expect(subject.instance_variable_get('@foo')).to eq('bar')
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with a token passed in" do
|
20
|
+
it "doesn't raise an error" do
|
21
|
+
expect { ContextIO::ConnectToken.new(api, token: '1234') }.to_not raise_error
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "with neither a provider_token nor a resource_url passed in" do
|
26
|
+
it "raises an ArgumentError" do
|
27
|
+
expect { ContextIO::ConnectToken.new(api, foo: 'bar') }.to raise_error(ArgumentError)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#token" do
|
33
|
+
context "when input at creation" do
|
34
|
+
subject { ContextIO::ConnectToken.new(api, token: '1234') }
|
35
|
+
|
36
|
+
it "uses the input key" do
|
37
|
+
api.should_not_receive(:request)
|
38
|
+
|
39
|
+
expect(subject.token).to eq('1234')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when not input at creation" do
|
44
|
+
subject { ContextIO::ConnectToken.new(api, resource_url: 'http://example.com/hitme') }
|
45
|
+
|
46
|
+
it "loads it from the API" do
|
47
|
+
api.should_receive(:request).with(
|
48
|
+
:get,
|
49
|
+
'http://example.com/hitme'
|
50
|
+
).and_return({
|
51
|
+
'token' => 'baphoo'
|
52
|
+
})
|
53
|
+
|
54
|
+
expect(subject.token).to eq('baphoo')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'contextio/email_settings'
|
3
|
+
|
4
|
+
describe ContextIO::EmailSettings do
|
5
|
+
let(:api) { double('API') }
|
6
|
+
|
7
|
+
subject { ContextIO::EmailSettings.new(api, 'email@email.com') }
|
8
|
+
|
9
|
+
describe ".new" do
|
10
|
+
context "without a source type passed in" do
|
11
|
+
it "takes an api handle" do
|
12
|
+
expect(subject.api).to eq(api)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "takes an email address" do
|
16
|
+
expect(subject.email).to eq('email@email.com')
|
17
|
+
end
|
18
|
+
|
19
|
+
it "defaults the source type to 'IMAP'" do
|
20
|
+
expect(subject.source_type).to eq('IMAP')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "with a source type passed in" do
|
25
|
+
subject { ContextIO::EmailSettings.new(api, 'email@email.com', 'FOO') }
|
26
|
+
|
27
|
+
it "takes a source type argument" do
|
28
|
+
expect(subject.source_type).to eq('FOO')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#resource_url" do
|
34
|
+
it "builds the right url" do
|
35
|
+
expect(subject.resource_url).to eq('discovery')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#documentation" do
|
40
|
+
it "fetches it from the api" do
|
41
|
+
api.should_receive(:request).with(:get, anything, anything).and_return({ 'documentation' => ['foo', 'bar'] })
|
42
|
+
expect(subject.documentation).to eq(['foo', 'bar'])
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#found?" do
|
47
|
+
it "fetches it from the api" do
|
48
|
+
api.should_receive(:request).with(:get, anything, anything).and_return({ 'found' => true })
|
49
|
+
expect(subject).to be_found
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#type" do
|
54
|
+
it "fetches it from the api" do
|
55
|
+
api.should_receive(:request).with(:get, anything, anything).and_return({ 'type' => 'gmail' })
|
56
|
+
expect(subject.type).to eq('gmail')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "#server" do
|
61
|
+
it "fetches it from the api" do
|
62
|
+
api.should_receive(:request).with(:get, anything, anything).and_return({ 'imap' => { 'server' => 'imap.gmail.com' }})
|
63
|
+
expect(subject.server).to eq('imap.gmail.com')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "#username" do
|
68
|
+
it "fetches it from the api" do
|
69
|
+
api.should_receive(:request).with(:get, anything, anything).and_return({ 'imap' => { 'username' => 'ben' }})
|
70
|
+
expect(subject.username).to eq('ben')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "#port" do
|
75
|
+
it "fetches it from the api" do
|
76
|
+
api.should_receive(:request).with(:get, anything, anything).and_return({ 'imap' => { 'port' => 993 }})
|
77
|
+
expect(subject.port).to eq(993)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "#oauth?" do
|
82
|
+
it "fetches it from the api" do
|
83
|
+
api.should_receive(:request).with(:get, anything, anything).and_return({ 'imap' => { 'oauth' => false }})
|
84
|
+
expect(subject).to_not be_oauth
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "#use_ssl?" do
|
89
|
+
it "fetches it from the api" do
|
90
|
+
api.should_receive(:request).with(:get, anything, anything).and_return({ 'imap' => { 'use_ssl' => false }})
|
91
|
+
expect(subject).to_not be_use_ssl
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "#fetch_attributes" do
|
96
|
+
before do
|
97
|
+
api.stub(:request).with(:get, anything, anything).and_return({ 'foo' => 'bar' })
|
98
|
+
end
|
99
|
+
|
100
|
+
it "defines a getter if one doesn't already exist" do
|
101
|
+
subject.send(:fetch_attributes)
|
102
|
+
|
103
|
+
expect(subject.foo).to eq('bar')
|
104
|
+
end
|
105
|
+
|
106
|
+
it "hits the right URL" do
|
107
|
+
api.should_receive(:request).with(:get, 'discovery', 'email' => 'email@email.com', 'source_type' => 'IMAP')
|
108
|
+
|
109
|
+
subject.send(:fetch_attributes)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|