washbullet 0.3.1 → 0.4.0

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