washbullet 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.rspec +1 -1
- data/.travis.yml +3 -0
- data/README.md +61 -24
- data/Rakefile +6 -1
- data/lib/washbullet.rb +5 -0
- data/lib/washbullet/api.rb +3 -1
- data/lib/washbullet/api/contacts.rb +13 -3
- data/lib/washbullet/api/devices.rb +9 -3
- data/lib/washbullet/api/me.rb +1 -1
- data/lib/washbullet/api/pushes.rb +14 -55
- data/lib/washbullet/api/subscriptions.rb +17 -0
- data/lib/washbullet/{basic_authentication.rb → authorization.rb} +1 -1
- data/lib/washbullet/channel.rb +29 -0
- data/lib/washbullet/client.rb +18 -18
- data/lib/washbullet/contact.rb +35 -0
- data/lib/washbullet/device.rb +27 -0
- data/lib/washbullet/entity.rb +27 -0
- data/lib/washbullet/http_exception.rb +19 -14
- data/lib/washbullet/push.rb +27 -0
- data/lib/washbullet/pushable.rb +59 -0
- data/lib/washbullet/pushable/file.rb +55 -0
- data/lib/washbullet/pushable/link.rb +13 -0
- data/lib/washbullet/pushable/note.rb +13 -0
- data/lib/washbullet/request.rb +1 -1
- data/lib/washbullet/user.rb +9 -0
- data/lib/washbullet/version.rb +1 -1
- data/spec/fixtures/green.png +0 -0
- data/spec/spec_helper.rb +48 -68
- data/spec/vcr/Washbullet_API_Contacts/_contacts/Get_own_active_contacts.yml +48 -0
- data/spec/vcr/Washbullet_API_Devices/_devices/Get_own_active_devices.yml +50 -0
- data/spec/vcr/Washbullet_API_Me/_me/Get_the_self_information.yml +50 -0
- data/spec/vcr/Washbullet_API_Subscriptions/_channel_info/when_channel_is_existing/Get_information_about_a_channel.yml +49 -0
- data/spec/vcr/Washbullet_API_Subscriptions/_channel_info/when_channel_is_not_existing/raise_error.yml +49 -0
- data/spec/vcr/Washbullet_API_Subscriptions/_subscriptions/Get_list_subscriptions.yml +50 -0
- data/spec/vcr/Washbullet_Pushable_File/_push/.yml +170 -0
- data/spec/vcr/Washbullet_Pushable_Link/_push/.yml +52 -0
- data/spec/vcr/Washbullet_Pushable_Note/_push/.yml +51 -0
- data/spec/washbullet/api/contacts_spec.rb +15 -0
- data/spec/washbullet/api/devices_spec.rb +14 -0
- data/spec/washbullet/api/me_spec.rb +11 -0
- data/spec/washbullet/api/subscriptions_spec.rb +31 -0
- data/spec/washbullet/pushable/file_spec.rb +23 -0
- data/spec/washbullet/pushable/link_spec.rb +24 -0
- data/spec/washbullet/pushable/note_spec.rb +20 -0
- data/washbullet.gemspec +5 -1
- metadata +107 -29
- data/spec/fixtures/contacts.json +0 -16
- data/spec/fixtures/devices.json +0 -19
- data/spec/fixtures/push.json +0 -18
- data/spec/fixtures/pushes.json +0 -24
- data/spec/fixtures/upload_request.json +0 -14
- data/spec/fixtures/users.json +0 -31
- data/spec/washbullet/client_spec.rb +0 -9
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'washbullet/entity'
|
2
|
+
|
3
|
+
module Washbullet
|
4
|
+
class Contact < Entity
|
5
|
+
def self.from_response(response)
|
6
|
+
response.body['contacts'].each_with_object([]) {|attributes, memo|
|
7
|
+
next unless attributes['active']
|
8
|
+
|
9
|
+
memo << new(attributes)
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
body['name']
|
15
|
+
end
|
16
|
+
|
17
|
+
def email
|
18
|
+
body['email']
|
19
|
+
end
|
20
|
+
|
21
|
+
def image_url
|
22
|
+
body['image_url']
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def receiver
|
28
|
+
:email
|
29
|
+
end
|
30
|
+
|
31
|
+
def identifier
|
32
|
+
body['email']
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'washbullet/entity'
|
2
|
+
|
3
|
+
module Washbullet
|
4
|
+
class Device < Entity
|
5
|
+
def self.from_response(response)
|
6
|
+
response.body['devices'].each_with_object([]) {|attributes, memo|
|
7
|
+
next unless attributes['active']
|
8
|
+
|
9
|
+
memo << new(attributes)
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def identifier
|
14
|
+
body['iden']
|
15
|
+
end
|
16
|
+
|
17
|
+
def nickname
|
18
|
+
body['nickname']
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def receiver
|
24
|
+
:device
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Washbullet
|
2
|
+
class Entity
|
3
|
+
attr_reader :body
|
4
|
+
|
5
|
+
def initialize(response_body)
|
6
|
+
@body = response_body
|
7
|
+
end
|
8
|
+
|
9
|
+
def created
|
10
|
+
Time.at(body['created'])
|
11
|
+
end
|
12
|
+
|
13
|
+
def modified
|
14
|
+
Time.at(body['modified'])
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def receiver
|
20
|
+
raise NotImplementedError
|
21
|
+
end
|
22
|
+
|
23
|
+
def identifier
|
24
|
+
raise NotImplementedError
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -9,21 +9,26 @@ module Washbullet
|
|
9
9
|
class HttpException < Faraday::Response::Middleware
|
10
10
|
def call(env)
|
11
11
|
@app.call(env).on_complete do |response|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
when 500..505
|
24
|
-
raise Washbullet::ServerError, 'Something went wrong on PushBullet\'s side'
|
25
|
-
end
|
12
|
+
exception =
|
13
|
+
case response.status
|
14
|
+
when 400 then Washbullet::BadRequest
|
15
|
+
when 401 then Washbullet::Unauthorized
|
16
|
+
when 402 then Washbullet::RequestFailed
|
17
|
+
when 403 then Washbullet::Forbidden
|
18
|
+
when 404 then Washbullet::NotFound
|
19
|
+
when 500..505 then Washbullet::ServerError
|
20
|
+
end
|
21
|
+
|
22
|
+
raise exception, error_message(response.body) if exception
|
26
23
|
end
|
27
24
|
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def error_message(response_body)
|
29
|
+
hash = JSON.parse(response_body)['error']
|
30
|
+
|
31
|
+
[hash['message'], hash['cat']].join(' ')
|
32
|
+
end
|
28
33
|
end
|
29
34
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Washbullet
|
2
|
+
class Push
|
3
|
+
attr_reader :body
|
4
|
+
|
5
|
+
def initialize(response_body)
|
6
|
+
@body = response_body
|
7
|
+
end
|
8
|
+
|
9
|
+
def type
|
10
|
+
body['type']
|
11
|
+
end
|
12
|
+
|
13
|
+
def created
|
14
|
+
Time.at(body['created'])
|
15
|
+
end
|
16
|
+
|
17
|
+
def modified
|
18
|
+
Time.at(body['modified'])
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def identifier
|
24
|
+
body['iden']
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'washbullet/push'
|
2
|
+
|
3
|
+
module Washbullet
|
4
|
+
class Pushable
|
5
|
+
class MissingParameter < StandardError; end
|
6
|
+
|
7
|
+
attr_reader :client, :receiver, :identifier, :params
|
8
|
+
|
9
|
+
def self.push(client, receiver, identifier, params)
|
10
|
+
response = new(client, receiver, identifier, params).push
|
11
|
+
|
12
|
+
Push.new(response.body)
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(client, receiver, identifier, params)
|
16
|
+
@client = client
|
17
|
+
@receiver = receiver
|
18
|
+
@identifier = identifier
|
19
|
+
@params = params
|
20
|
+
end
|
21
|
+
|
22
|
+
def push
|
23
|
+
raise MissingParameter unless params.keys == required_parameters
|
24
|
+
|
25
|
+
payload = params.merge(type: type)
|
26
|
+
|
27
|
+
payload = specify_receiver(payload)
|
28
|
+
|
29
|
+
client.post('/v2/pushes', payload)
|
30
|
+
end
|
31
|
+
|
32
|
+
def type
|
33
|
+
raise NotImplementedError
|
34
|
+
end
|
35
|
+
|
36
|
+
def required_parameters
|
37
|
+
raise NotImplementedError
|
38
|
+
end
|
39
|
+
|
40
|
+
def specify_receiver(payload)
|
41
|
+
if receiver && identifier
|
42
|
+
payload.merge(receiver_type => identifier)
|
43
|
+
else
|
44
|
+
payload
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def receiver_type
|
49
|
+
case receiver
|
50
|
+
when :device then :device_iden
|
51
|
+
when :email then receiver
|
52
|
+
when :channel then :channel_tag
|
53
|
+
when :client then :client_iden
|
54
|
+
else
|
55
|
+
raise NotImplementedError
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Washbullet
|
2
|
+
class Pushable
|
3
|
+
class File < Washbullet::Pushable
|
4
|
+
def push
|
5
|
+
raise MissingParameter unless params.keys == required_parameters
|
6
|
+
|
7
|
+
file_name = params[:file_name]
|
8
|
+
file_path = params[:file_path]
|
9
|
+
|
10
|
+
upload_file(file_name, file_path) do |data|
|
11
|
+
payload = {
|
12
|
+
file_name: data['file_name'],
|
13
|
+
file_type: data['file_type'],
|
14
|
+
file_url: data['file_url'],
|
15
|
+
body: params['body'],
|
16
|
+
type: type
|
17
|
+
}
|
18
|
+
|
19
|
+
payload = specify_receiver(payload)
|
20
|
+
|
21
|
+
client.post('/v2/pushes', payload)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def type
|
26
|
+
:file
|
27
|
+
end
|
28
|
+
|
29
|
+
def required_parameters
|
30
|
+
%i(file_name file_path body)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def upload_file(file_name, file_path, &block)
|
36
|
+
mime_type = MIME::Types.type_for(file_path).first.to_s
|
37
|
+
|
38
|
+
data = upload_request(file_name, mime_type)
|
39
|
+
|
40
|
+
upload_url = data.body['upload_url']
|
41
|
+
params = data.body['data']
|
42
|
+
|
43
|
+
io = Faraday::UploadIO.new(file_path, mime_type)
|
44
|
+
|
45
|
+
client.post upload_url, params.merge(file: io)
|
46
|
+
|
47
|
+
yield data.body
|
48
|
+
end
|
49
|
+
|
50
|
+
def upload_request(file_name, mime_type)
|
51
|
+
client.post '/v2/upload-request', file_name: file_name, file_type: mime_type
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/washbullet/request.rb
CHANGED
@@ -15,7 +15,7 @@ module Washbullet
|
|
15
15
|
private
|
16
16
|
|
17
17
|
def request(method, path, params = {})
|
18
|
-
|
18
|
+
connection.send(method) {|request|
|
19
19
|
request.url path
|
20
20
|
request.params = params if method == :get
|
21
21
|
request.body = params if method == :post
|
data/lib/washbullet/version.rb
CHANGED
Binary file
|
data/spec/spec_helper.rb
CHANGED
@@ -1,82 +1,62 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# The generated `.rspec` file contains `--require spec_helper` which will cause this
|
4
|
-
# file to always be loaded, without a need to explicitly require it in any files.
|
5
|
-
#
|
6
|
-
# Given that it is always loaded, you are encouraged to keep this file as
|
7
|
-
# light-weight as possible. Requiring heavyweight dependencies from this file
|
8
|
-
# (such as loading up an entire rails app) will add to the boot time of your
|
9
|
-
# test suite on EVERY test run, even for an individual file that may not need
|
10
|
-
# all of that loaded.
|
11
|
-
#
|
12
|
-
# The `.rspec` file also contains a few flags that are not defaults but that
|
13
|
-
# users commonly want.
|
14
|
-
#
|
15
|
-
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
16
|
-
RSpec.configure do |config|
|
17
|
-
# The settings below are suggested to provide a good initial experience
|
18
|
-
# with RSpec, but feel free to customize to your heart's content.
|
19
|
-
=begin
|
20
|
-
# These two settings work together to allow you to limit a spec run
|
21
|
-
# to individual examples or groups you care about by tagging them with
|
22
|
-
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
|
23
|
-
# get run.
|
24
|
-
config.filter_run :focus
|
25
|
-
config.run_all_when_everything_filtered = true
|
1
|
+
require 'pry'
|
2
|
+
require 'json'
|
26
3
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
config.full_backtrace = true
|
4
|
+
require 'washbullet'
|
5
|
+
require 'webmock/rspec'
|
6
|
+
require 'vcr'
|
7
|
+
|
8
|
+
def test_api_key
|
9
|
+
ENV.fetch('API_KEY', '<API_KEY>')
|
10
|
+
end
|
35
11
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
12
|
+
VCR.configure do |config|
|
13
|
+
config.cassette_library_dir = 'spec/vcr'
|
14
|
+
config.hook_into :webmock
|
15
|
+
config.configure_rspec_metadata!
|
16
|
+
|
17
|
+
config.filter_sensitive_data('<API_KEY>') do
|
18
|
+
test_api_key
|
40
19
|
end
|
41
20
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
21
|
+
config.before_record do |interaction|
|
22
|
+
next if interaction.response.body.empty?
|
23
|
+
|
24
|
+
response = JSON.parse(interaction.response.body)
|
25
|
+
|
26
|
+
response['iden'] = '<IDENTIFIER>' if response.has_key?('iden')
|
27
|
+
|
28
|
+
%w(devices contacts subscriptions).each do |key|
|
29
|
+
response[key] = response[key].map {|entity|
|
30
|
+
entity.merge!({'iden' => '<IDENTIFIER>'})
|
46
31
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
config.order = :random
|
32
|
+
if entity['fingerprint']
|
33
|
+
entity['fingerprint'] = JSON.parse(entity['fingerprint'])
|
34
|
+
entity['fingerprint'].merge!({'android_id' => '<ANDROID_ID>'})
|
35
|
+
end
|
52
36
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
# as the one that triggered the failure.
|
57
|
-
Kernel.srand config.seed
|
37
|
+
if entity['channel']
|
38
|
+
entity['channel'].merge!({'iden' => '<IDENTIFIER>'})
|
39
|
+
end
|
58
40
|
|
59
|
-
|
60
|
-
|
61
|
-
|
41
|
+
entity
|
42
|
+
} if response[key]
|
43
|
+
end
|
44
|
+
|
45
|
+
interaction.response.body = response.to_json
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
RSpec.configure do |config|
|
62
50
|
config.expect_with :rspec do |expectations|
|
63
|
-
|
64
|
-
# For more details, see:
|
65
|
-
# - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
|
66
|
-
expectations.syntax = :expect
|
51
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
67
52
|
end
|
68
53
|
|
69
|
-
# rspec-mocks config goes here. You can use an alternate test double
|
70
|
-
# library (such as bogus or mocha) by changing the `mock_with` option here.
|
71
54
|
config.mock_with :rspec do |mocks|
|
72
|
-
# Enable only the newer, non-monkey-patching expect syntax.
|
73
|
-
# For more details, see:
|
74
|
-
# - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
75
|
-
mocks.syntax = :expect
|
76
|
-
|
77
|
-
# Prevents you from mocking or stubbing a method that does not exist on
|
78
|
-
# a real object. This is generally recommended.
|
79
55
|
mocks.verify_partial_doubles = true
|
80
56
|
end
|
81
|
-
|
57
|
+
|
58
|
+
config.filter_run :focus
|
59
|
+
config.run_all_when_everything_filtered = true
|
60
|
+
config.disable_monkey_patching!
|
61
|
+
config.warnings = true
|
82
62
|
end
|