washbullet 0.3.1 → 0.4.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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.rspec +1 -1
  4. data/.travis.yml +3 -0
  5. data/README.md +61 -24
  6. data/Rakefile +6 -1
  7. data/lib/washbullet.rb +5 -0
  8. data/lib/washbullet/api.rb +3 -1
  9. data/lib/washbullet/api/contacts.rb +13 -3
  10. data/lib/washbullet/api/devices.rb +9 -3
  11. data/lib/washbullet/api/me.rb +1 -1
  12. data/lib/washbullet/api/pushes.rb +14 -55
  13. data/lib/washbullet/api/subscriptions.rb +17 -0
  14. data/lib/washbullet/{basic_authentication.rb → authorization.rb} +1 -1
  15. data/lib/washbullet/channel.rb +29 -0
  16. data/lib/washbullet/client.rb +18 -18
  17. data/lib/washbullet/contact.rb +35 -0
  18. data/lib/washbullet/device.rb +27 -0
  19. data/lib/washbullet/entity.rb +27 -0
  20. data/lib/washbullet/http_exception.rb +19 -14
  21. data/lib/washbullet/push.rb +27 -0
  22. data/lib/washbullet/pushable.rb +59 -0
  23. data/lib/washbullet/pushable/file.rb +55 -0
  24. data/lib/washbullet/pushable/link.rb +13 -0
  25. data/lib/washbullet/pushable/note.rb +13 -0
  26. data/lib/washbullet/request.rb +1 -1
  27. data/lib/washbullet/user.rb +9 -0
  28. data/lib/washbullet/version.rb +1 -1
  29. data/spec/fixtures/green.png +0 -0
  30. data/spec/spec_helper.rb +48 -68
  31. data/spec/vcr/Washbullet_API_Contacts/_contacts/Get_own_active_contacts.yml +48 -0
  32. data/spec/vcr/Washbullet_API_Devices/_devices/Get_own_active_devices.yml +50 -0
  33. data/spec/vcr/Washbullet_API_Me/_me/Get_the_self_information.yml +50 -0
  34. data/spec/vcr/Washbullet_API_Subscriptions/_channel_info/when_channel_is_existing/Get_information_about_a_channel.yml +49 -0
  35. data/spec/vcr/Washbullet_API_Subscriptions/_channel_info/when_channel_is_not_existing/raise_error.yml +49 -0
  36. data/spec/vcr/Washbullet_API_Subscriptions/_subscriptions/Get_list_subscriptions.yml +50 -0
  37. data/spec/vcr/Washbullet_Pushable_File/_push/.yml +170 -0
  38. data/spec/vcr/Washbullet_Pushable_Link/_push/.yml +52 -0
  39. data/spec/vcr/Washbullet_Pushable_Note/_push/.yml +51 -0
  40. data/spec/washbullet/api/contacts_spec.rb +15 -0
  41. data/spec/washbullet/api/devices_spec.rb +14 -0
  42. data/spec/washbullet/api/me_spec.rb +11 -0
  43. data/spec/washbullet/api/subscriptions_spec.rb +31 -0
  44. data/spec/washbullet/pushable/file_spec.rb +23 -0
  45. data/spec/washbullet/pushable/link_spec.rb +24 -0
  46. data/spec/washbullet/pushable/note_spec.rb +20 -0
  47. data/washbullet.gemspec +5 -1
  48. metadata +107 -29
  49. data/spec/fixtures/contacts.json +0 -16
  50. data/spec/fixtures/devices.json +0 -19
  51. data/spec/fixtures/push.json +0 -18
  52. data/spec/fixtures/pushes.json +0 -24
  53. data/spec/fixtures/upload_request.json +0 -14
  54. data/spec/fixtures/users.json +0 -31
  55. 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
- case response[:status].to_i
13
- when 400
14
- raise Washbullet::BadRequest, 'Often missing a required parameter'
15
- when 401
16
- raise Washbullet::Unauthorized, 'No valid API key provided'
17
- when 402
18
- raise Washbullet::RequestFailed, 'Parameters were valid but the request failed'
19
- when 403
20
- raise Washbullet::Forbidden, 'The API key is not valid for that request'
21
- when 404
22
- raise Washbullet::NotFound, 'The requested item doesn\'t exist'
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
@@ -0,0 +1,13 @@
1
+ module Washbullet
2
+ class Pushable
3
+ class Link < Washbullet::Pushable
4
+ def type
5
+ :link
6
+ end
7
+
8
+ def required_parameters
9
+ %i(title url body)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Washbullet
2
+ class Pushable
3
+ class Note < Pushable
4
+ def type
5
+ :note
6
+ end
7
+
8
+ def required_parameters
9
+ %i(title body)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -15,7 +15,7 @@ module Washbullet
15
15
  private
16
16
 
17
17
  def request(method, path, params = {})
18
- response = connection.send(method) {|request|
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
@@ -0,0 +1,9 @@
1
+ require 'washbullet/entity'
2
+
3
+ module Washbullet
4
+ class User < Entity
5
+ def identifier
6
+ body['iden']
7
+ end
8
+ end
9
+ end
@@ -1,3 +1,3 @@
1
1
  module Washbullet
2
- VERSION = '0.3.1'
2
+ VERSION = '0.4.0'
3
3
  end
Binary file
@@ -1,82 +1,62 @@
1
- # This file was generated by the `rspec --init` command. Conventionally, all
2
- # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
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
- # Many RSpec users commonly either run the entire suite or an individual
28
- # file, and it's useful to allow more verbose output when running an
29
- # individual spec file.
30
- if config.files_to_run.one?
31
- # RSpec filters the backtrace by default so as not to be so noisy.
32
- # This causes the full backtrace to be printed when running a single
33
- # spec file (e.g. to troubleshoot a particular spec failure).
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
- # Use the documentation formatter for detailed output,
37
- # unless a formatter has already been configured
38
- # (e.g. via a command-line flag).
39
- config.formatter = 'doc' if config.formatters.none?
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
- # Print the 10 slowest examples and example groups at the
43
- # end of the spec run, to help surface which specs are running
44
- # particularly slow.
45
- config.profile_examples = 10
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
- # Run specs in random order to surface order dependencies. If you find an
48
- # order dependency and want to debug it, you can fix the order by providing
49
- # the seed, which is printed after each run.
50
- # --seed 1234
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
- # Seed global randomization in this process using the `--seed` CLI option.
54
- # Setting this allows you to use `--seed` to deterministically reproduce
55
- # test failures related to randomization by passing the same `--seed` value
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
- # rspec-expectations config goes here. You can use an alternate
60
- # assertion/expectation library such as wrong or the stdlib/minitest
61
- # assertions if you prefer.
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
- # Enable only the newer, non-monkey-patching expect syntax.
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
- =end
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