phaxio 0.4.0 → 2.1.0.pre

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 (85) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.travis.yml +11 -0
  4. data/Gemfile +11 -5
  5. data/README.md +296 -40
  6. data/Rakefile +7 -9
  7. data/lib/phaxio.rb +48 -3
  8. data/lib/phaxio/client.rb +151 -241
  9. data/lib/phaxio/config.rb +31 -0
  10. data/lib/phaxio/error.rb +13 -0
  11. data/lib/phaxio/helpers/mime_type_helper.rb +14 -0
  12. data/lib/phaxio/resource.rb +168 -0
  13. data/lib/phaxio/resources.rb +7 -0
  14. data/lib/phaxio/resources/account.rb +41 -0
  15. data/lib/phaxio/resources/ata.rb +219 -0
  16. data/lib/phaxio/resources/callback.rb +65 -0
  17. data/lib/phaxio/resources/fax.rb +310 -0
  18. data/lib/phaxio/resources/fax_recipient.rb +41 -0
  19. data/lib/phaxio/resources/phax_code.rb +89 -0
  20. data/lib/phaxio/resources/phone_number.rb +112 -0
  21. data/lib/phaxio/resources/public.rb +8 -0
  22. data/lib/phaxio/resources/public/area_code.rb +64 -0
  23. data/lib/phaxio/resources/public/country.rb +54 -0
  24. data/lib/phaxio/version.rb +1 -1
  25. data/phaxio.gemspec +10 -8
  26. data/spec/client_spec.rb +164 -0
  27. data/spec/helpers/mime_type_helper_spec.rb +11 -0
  28. data/spec/phaxio_spec.rb +20 -0
  29. data/spec/resources/account_spec.rb +24 -0
  30. data/spec/resources/callback_spec.rb +34 -0
  31. data/spec/resources/fax_spec.rb +248 -0
  32. data/spec/resources/phax_code_spec.rb +111 -0
  33. data/spec/resources/phone_number_spec.rb +89 -0
  34. data/spec/resources/public/area_code_spec.rb +24 -0
  35. data/spec/resources/public/country_spec.rb +24 -0
  36. data/spec/spec_helper.rb +6 -0
  37. data/spec/support/credentials.rb +7 -0
  38. data/spec/support/expectations.rb +9 -0
  39. data/spec/support/files/test.pdf +0 -0
  40. data/spec/support/files/test.txt +1 -0
  41. data/spec/support/vcr.rb +8 -0
  42. data/spec/support/vcr_cassettes/resources/account/status.yml +45 -0
  43. data/spec/support/vcr_cassettes/resources/fax/cancel.yml +47 -0
  44. data/spec/support/vcr_cassettes/resources/fax/create.yml +50 -0
  45. data/spec/support/vcr_cassettes/resources/fax/create_for_cancel.yml +50 -0
  46. data/spec/support/vcr_cassettes/resources/fax/create_for_delete.yml +50 -0
  47. data/spec/support/vcr_cassettes/resources/fax/create_for_delete_file.yml +50 -0
  48. data/spec/support/vcr_cassettes/resources/fax/create_for_download_file.yml +50 -0
  49. data/spec/support/vcr_cassettes/resources/fax/create_for_get.yml +50 -0
  50. data/spec/support/vcr_cassettes/resources/fax/create_for_reference.yml +50 -0
  51. data/spec/support/vcr_cassettes/resources/fax/create_for_resend.yml +50 -0
  52. data/spec/support/vcr_cassettes/resources/fax/delete.yml +45 -0
  53. data/spec/support/vcr_cassettes/resources/fax/delete_file.yml +45 -0
  54. data/spec/support/vcr_cassettes/resources/fax/file.yml +50 -0
  55. data/spec/support/vcr_cassettes/resources/fax/get.yml +45 -0
  56. data/spec/support/vcr_cassettes/resources/fax/list.yml +51 -0
  57. data/spec/support/vcr_cassettes/resources/fax/reference.yml +45 -0
  58. data/spec/support/vcr_cassettes/resources/fax/resend.yml +47 -0
  59. data/spec/support/vcr_cassettes/resources/fax/test_receive.yml +51 -0
  60. data/spec/support/vcr_cassettes/resources/phax_code/create.yml +47 -0
  61. data/spec/support/vcr_cassettes/resources/phax_code/create_png.yml +52 -0
  62. data/spec/support/vcr_cassettes/resources/phax_code/get.yml +45 -0
  63. data/spec/support/vcr_cassettes/resources/phax_code/get_id.yml +46 -0
  64. data/spec/support/vcr_cassettes/resources/phax_code/get_id_png.yml +50 -0
  65. data/spec/support/vcr_cassettes/resources/phax_code/get_png.yml +50 -0
  66. data/spec/support/vcr_cassettes/resources/phone_number/create.yml +48 -0
  67. data/spec/support/vcr_cassettes/resources/phone_number/get.yml +46 -0
  68. data/spec/support/vcr_cassettes/resources/phone_number/list.yml +60 -0
  69. data/spec/support/vcr_cassettes/resources/phone_number/release.yml +45 -0
  70. data/spec/support/vcr_cassettes/resources/public/area_codes/list.yml +79 -0
  71. data/spec/support/vcr_cassettes/resources/public/country/list.yml +55 -0
  72. metadata +103 -73
  73. data/test/support/responses/account_status.json +0 -9
  74. data/test/support/responses/cancel_success.json +0 -4
  75. data/test/support/responses/fax_status_success.json +0 -21
  76. data/test/support/responses/list_faxes.json +0 -68
  77. data/test/support/responses/list_numbers.json +0 -22
  78. data/test/support/responses/provision_number.json +0 -12
  79. data/test/support/responses/release_number.json +0 -7
  80. data/test/support/responses/send_failure.json +0 -8
  81. data/test/support/responses/send_success.json +0 -8
  82. data/test/support/responses/test.pdf +0 -0
  83. data/test/support/responses/test_receive.json +0 -4
  84. data/test/test_helper.rb +0 -53
  85. data/test/test_phaxio.rb +0 -72
data/lib/phaxio/client.rb CHANGED
@@ -1,259 +1,169 @@
1
+ # @!macro [new] paging
2
+ # @note
3
+ # This action accepts paging parameters:
4
+ # - *per_page* [Integer] - The maximum number of results to return per
5
+ # call (i.e. "page"). Max 1000.
6
+ # - *page* [Integer] - The page number to return for the request. 1-based.
7
+
1
8
  module Phaxio
2
- include HTTMultiParty
3
- base_uri 'https://api.phaxio.com/v1'
9
+ # @api private
4
10
 
5
- module Config
6
- attr_accessor :api_key, :api_secret
7
- end
11
+ class Client
12
+ class << self
13
+ # Makes a request to the Phaxio API.
14
+ #
15
+ # @param method [Symbol, String]
16
+ # The HTTP method for the request. Currently only `:get`, `:post`, and `:delete` are
17
+ # supported.
18
+ # @param endpoint [String]
19
+ # The endpoint for the API action, relative to `Phaxio::Config.api_endpoint`.
20
+ # @param params [Hash]
21
+ # Any parameters to be sent with the request.
22
+ #
23
+ # @return [Object]
24
+ # The `"data"` attribute of the deserialized JSON response. Varies based on the API action.
25
+ def request method, endpoint, params = {}
26
+ params = api_params params
27
+ begin
28
+ response = case method.to_s
29
+ when 'post' then post(endpoint, params)
30
+ when 'patch' then patch(endpoint, params)
31
+ when 'get' then get(endpoint, params)
32
+ when 'delete' then delete(endpoint, params)
33
+ else raise ArgumentError, "HTTP method `#{method}` is not supported."
34
+ end
35
+ handle_response response
36
+ rescue Faraday::ConnectionFailed, Faraday::TimeoutError, Faraday::SSLError => error
37
+ raise Error::ApiConnectionError, "Error communicating with Phaxio: #{error}"
38
+ end
39
+ end
8
40
 
9
- module Client
10
- # Public: Send a fax.
11
- #
12
- # options - The Hash options used to refine the selection (default: {}):
13
- # :to - The Phone Number (i.e. [country
14
- # code][number] or just a 10 digit
15
- # number in the US or Canada). Put
16
- # square brackets after parameter
17
- # name to send to multiple
18
- # recipients (e.g. to[]) (required).
19
- # :filename - The Binary Stream name of the file
20
- # you want to fax. This is optional
21
- # if you specify string_data. Must
22
- # have file name in the filename
23
- # field of the body-part header. Put
24
- # square brackets after parameter
25
- # name to send multiple files (e.g.
26
- # filename[]) (required).
27
- # :string_data - A String of html, plain text, or a
28
- # URL. If additional files are
29
- # specified as well, this data will
30
- # be included first in the fax
31
- # (optional).
32
- # :string_data_type - An enum of the type of the string
33
- # data that can be 'html', 'url', or
34
- # 'text'. If not specified, default
35
- # is 'text'. See string data
36
- # rendering for more info (optional).
37
- # :batch - The bool for running in batching
38
- # mode. If present and true, fax will
39
- # be sent in batching mode. Requires
40
- # batch_delay to be specified
41
- # (optional).
42
- # :batch_delay - The int the of amount of time, in
43
- # seconds, before the batch is fired.
44
- # Must be specified if batch=true.
45
- # Maximum delay is 3600 (1 hour)
46
- # (optional).
47
- # :batch_collision_avoidance - The bool for collision avoidance
48
- # with batches. If true when
49
- # batch=true, fax will be blocked
50
- # until the receiving machine is no
51
- # longer busy (optional).
52
- # :callback_url - The String url for the callback.
53
- # Overrides the globally set one
54
- # (optional).
55
- # :cancel_timeout - An int of the number of minutes
56
- # after which the fax will be
57
- # canceled if it hasn't yet
58
- # completed. Must be between 1 and 60
59
- # (optional).
60
- #
61
- # Examples
62
- #
63
- # Phaxio.send_fax(to: "0123456789", filename: "test.pdf")
64
- #
65
- # Returns a HTTParty::Response object containing a success bool,
66
- # a String message, and an in faxID.
67
- def send_fax(options)
68
- send_post("/send", options)
69
- end
41
+ # @return [Faraday::Connection] A new Faraday connection to `Phaxio::Config.api_endpoint`.
42
+ def conn
43
+ Faraday.new(Phaxio.api_endpoint) do |conn|
44
+ conn.request :multipart
45
+ conn.request :url_encoded
46
+ conn.adapter :net_http
70
47
 
71
- # Public: Test receiving a fax.
72
- #
73
- # options - The Hash options used to refine the selection (default: {}):
74
- # from_number - The Phone Number of the simulated sender
75
- # (optional).
76
- # to_number - The Phone Number receiving the fax (optional).
77
- # filename - A String containing the name of the PDF that has
78
- # a PhaxCode and is the file you want to simulate
79
- # sending (required).
80
- #
81
- # Examples
82
- #
83
- # Phaxio.test_receive(filename: "test_file.pdf")
84
- #
85
- # Returns a HTTParty::Response object containing a success bool
86
- # and a String message.
87
- def test_receive(options)
88
- send_post("/testReceive", options)
89
- end
48
+ if Phaxio.api_key && Phaxio.api_secret
49
+ conn.basic_auth Phaxio.api_key, Phaxio.api_secret
50
+ end
51
+ end
52
+ end
90
53
 
91
- # Public: Provision a phone number that you can use to receive faxes in
92
- # your Phaxio account.
93
- #
94
- # options - The Hash options used to refine the selection (default: {}):
95
- # area_code - The integer area code of the number you'd like
96
- # to provision (required).
97
- # callback_url - A callback URL that Phaxio will post to when a
98
- # fax is received by this number. This will
99
- # override the global receive callback URL, if you
100
- # have one set (optional).
101
- #
102
- # Examples
103
- #
104
- # Phaxio.provision_number(area_code: 802)
105
- #
106
- # Returns a HTTParty::Response object containing a success bool, a string
107
- # message, and data containing the phone number, city, state, cost,
108
- # last_billed_at, and the date the number was provisioned at.
109
- def provision_number(options)
110
- send_post("/provisionNumber", options)
111
- end
54
+ private
112
55
 
113
- # Public: Release a phone number that you no longer need. Once a phone
114
- # number is released you will no longer be charged for it.
115
- #
116
- # options - The Hash options used to refine the selection (default: {}):
117
- # number - The String of the phone number you want to release
118
- # (required).
119
- #
120
- # Examples
121
- #
122
- # Phaxio.release_number(number: "8021112222")
123
- #
124
- # Returns a HTTParty::Response object containing a success bool and a
125
- # string message.
126
- def release_number(options)
127
- send_post("/releaseNumber", options)
128
- end
56
+ def handle_response response
57
+ content_type = response.headers[:content_type]
129
58
 
130
- # Public: Get a detailed list of the phone numbers you current own on
131
- # Phaxio.
132
- #
133
- # options - The Hash options used to refne th selection (default: {}):
134
- # area_code - An integer area code you'd like to filter by
135
- # (optional).
136
- # number - A String phone number you'd like to retrieve
137
- # (optional).
138
- #
139
- # Examples
140
- #
141
- # Phaxio.list_numbers # list all the numbers you own
142
- #
143
- # Phaxio.list_numbers(area_code: 802) # list all numbers in the 802 area
144
- #
145
- # Phaxio.list_numbers(number: "8021112222") # show specific number detail
146
- #
147
- # Returns a HTTParty::Reponse object containing a success bool, a message,
148
- # and the data attributes containing the queried phone number(s) details.
149
- def list_numbers(options = {})
150
- send_post("/numberList", options)
151
- end
59
+ if content_type.start_with? 'application/json'
60
+ body = JSON.parse(response.body).with_indifferent_access
61
+ else
62
+ extension = MimeTypeHelper.extension_for_mimetype content_type
63
+ filename = File.join Dir.tmpdir, tmpname(extension)
64
+ File.open(filename, 'wb') { |file| file.write response.body }
65
+ body = {'success' => response.success?, 'data' => File.open(filename, 'rb')}
66
+ end
152
67
 
153
- # Public: Get an image thumbnail or PDF file for a fax. For images to work
154
- # file storage must not be disabled with Phaxio.
155
- #
156
- # options - The Hash options used to refine the selection (default: {}):
157
- # id - The integer fax id of the fax you wish to retreive
158
- # (required).
159
- # type - An enum for the type return, defaults to 'p' (optional):
160
- # s - Small JPG format thumbnail of the fax, 129 x 167 px.
161
- # l - Large JPG format thumbnail of the fax, 300 x 388 px.
162
- # p - PDF version of the fax (default).
163
- #
164
- # Examples
165
- #
166
- # Phaxio.get_fax_file(id: 1234, type: p)
167
- # Phaxio.get_fax_file(id: 3254, type: l)
168
- #
169
- # Returns the fax as the type specified in the call, defaults to PDF.
170
- def get_fax_file(options)
171
- send_post("/faxFile", options)
172
- end
68
+ if response.success?
69
+ raise(Error::GeneralError, body['message']) unless body['success']
173
70
 
174
- # Public: List faxes within the specified time range.
175
- #
176
- # options - The Hash options used to refine the selection (default: {}):
177
- # start - The Unix Timestamp for the beginning of the range
178
- # (required).
179
- # end - The Unix Timestamp for the end of the range (required).
180
- #
181
- # Examples
182
- #
183
- # Phaxio.list_faxes(start: 1293861600, end: 1294034400)
184
- #
185
- # Returns a HTTParty::Response object containing a success bool, a string
186
- # message, paging information, and the fax data.
187
- def list_faxes(options)
188
- send_post("/faxList", options)
189
- end
71
+ # Check if this is a response with paging. If so, we want to return that along with the
72
+ # data.
73
+ if body.key? 'paging'
74
+ {'data' => body['data'], 'paging' => body['paging']}
75
+ else
76
+ body['data']
77
+ end
78
+ else
79
+ status = response.status
80
+ # TODO: Handle blank message
81
+ message = body['message']
190
82
 
191
- # Public: Get the status of a specific fax.
192
- #
193
- # options - The Hash options used to refine the selection (default: {}):
194
- # id - The int id of the fax you want to get the status of
195
- # (required).
196
- #
197
- # Examples
198
- #
199
- # Phaxio.get_fax_status(id: "123456")
200
- #
201
- # Returns a HTTParty::Response object containing a success bool,
202
- # a String message, and the data of the fax.
203
- def get_fax_status(options)
204
- if options[:id].nil?
205
- raise StandardError, "You must include a fax id."
83
+ case status
84
+ when 401
85
+ raise Error::AuthenticationError, "#{status}: #{message}"
86
+ when 404
87
+ raise Error::NotFoundError, "#{status}: #{message}"
88
+ when 422
89
+ raise Error::InvalidRequestError, "#{status}: #{message}"
90
+ when 429
91
+ raise Error::RateLimitExceededError, "#{status}: #{message}"
92
+ else
93
+ raise Error::GeneralError, "#{status}: #{message}"
94
+ end
95
+ end
206
96
  end
207
97
 
208
- send_post("/faxStatus", options)
209
- end
98
+ def tmpname(extension)
99
+ t = Time.now.strftime("%Y%m%d")
100
+ "phaxio-#{t}-#{$$}-#{rand(0x100000000).to_s(36)}-download.#{extension}"
101
+ end
210
102
 
211
- # Public: Cancel a specific fax.
212
- #
213
- # options - The Hash options used to refine the selection (defaults: {}):
214
- # id - The int id of the fax you want to cancel (required).
215
- #
216
- # Examples
217
- #
218
- # Phaxio.cancel_fax(id: "123456")
219
- #
220
- # Returns a HTTParty::Response object containing a success bool
221
- # and a String message.
222
- def cancel_fax(options)
223
- send_post("/faxCancel", options)
224
- end
103
+ def post endpoint, params = {}
104
+ # Handle file params
105
+ params.each do |k, v|
106
+ next unless k.to_s == 'file'
225
107
 
226
- # Public: Get the status of Client's account.
227
- #
228
- # Examples
229
- #
230
- # Phaxio.get_account_status
231
- #
232
- # Returns a HTTParty::Response object with success, message, and data
233
- # (containing faxes_sent_this_month, faxes_sent_today, and balance).
234
- def get_account_status
235
- send_post("/accountStatus", {})
236
- end
108
+ if v.is_a? Array
109
+ file_param = v.map { |file| file_to_param file }
110
+ else
111
+ file_param = file_to_param v
112
+ end
237
113
 
238
- def send_post(path, options)
239
- post(path, query: options.merge!({api_key: api_key, api_secret: api_secret}))
240
- end
241
- end
114
+ params[k] = file_param
115
+ end
242
116
 
243
- # Public: Configure Phaxio with your api_key and api_secret
244
- #
245
- # Examples
246
- #
247
- # Phaxio.config do |config|
248
- # config.api_key = "12345678910"
249
- # config.api_secret = "10987654321"
250
- # end
251
- #
252
- # Returns nothing.
253
- def self.config
254
- yield(self)
255
- end
117
+ conn.post endpoint, params, api_headers(params)
118
+ end
119
+
120
+ def patch endpoint, params = {}
121
+ # Handle file params
122
+ params.each do |k, v|
123
+ next unless k.to_s == 'file'
124
+
125
+ if v.is_a? Array
126
+ file_param = v.map { |file| file_to_param file }
127
+ else
128
+ file_param = file_to_param v
129
+ end
130
+
131
+ params[k] = file_param
132
+ end
133
+
134
+ conn.patch endpoint, params, api_headers(params)
135
+ end
136
+
137
+ def get endpoint, params = {}
138
+ conn.get endpoint, params, api_headers(params)
139
+ end
140
+
141
+ def delete endpoint, params = {}
142
+ conn.delete endpoint, params, api_headers(params)
143
+ end
144
+
145
+ def api_params params
146
+ # Convert times to ISO 8601
147
+ params.each do |k, v|
148
+ next unless v.kind_of?(Time) || v.kind_of?(Date)
149
+ params[k] = v.to_datetime.iso8601
150
+ end
256
151
 
257
- extend Client
258
- extend Config
152
+ params
153
+ end
154
+
155
+ def api_headers params
156
+ api_key = params[:api_key] || Phaxio.api_key
157
+ api_secret = params[:api_secret] || Phaxio.api_secret
158
+ return unless api_key && api_secret
159
+ auth = Base64.strict_encode64("#{api_key}:#{api_secret}")
160
+ {'Authorization' => "Basic #{auth}"}
161
+ end
162
+
163
+ def file_to_param file
164
+ mime_type = MimeTypeHelper.mimetype_for_file file.path
165
+ Faraday::UploadIO.new file, mime_type
166
+ end
167
+ end
168
+ end
259
169
  end
@@ -0,0 +1,31 @@
1
+ module Phaxio
2
+ class Config
3
+ DEFAULT_API_ENDPOINT = 'https://api.phaxio.com/v2.1/'.freeze
4
+
5
+ class << self
6
+ # Your Phaxio API key. This will be used for all interactions with the Phaxio API.
7
+ #
8
+ # To find your API key, visit https://console.phaxio.com/api_credentials
9
+ attr_accessor :api_key
10
+
11
+ # Your Phaxio API secret. This will be used for all interactions with the Phaxio API.
12
+ #
13
+ # To find your API secret, visit https://console.phaxio.com/api_credentials
14
+ attr_accessor :api_secret
15
+
16
+ # Your Phaxio callback token. This will be used to verify that callback requests are coming
17
+ # from Phaxio.
18
+ #
19
+ # To find your callback token, visit https://console.phaxio.com/user/callbacks/edit
20
+ attr_accessor :callback_token
21
+
22
+ # The Phaxio API endpoint. Users generally shouldn't need to change it.
23
+ # Defaults to https://api.phaxio.com/v2/
24
+ attr_writer :api_endpoint
25
+
26
+ def api_endpoint
27
+ @api_endpoint || DEFAULT_API_ENDPOINT
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ module Phaxio
2
+ module Error
3
+ PhaxioError = Class.new StandardError
4
+ %w[
5
+ AuthenticationError
6
+ NotFoundError
7
+ InvalidRequestError
8
+ RateLimitExceededError
9
+ GeneralError
10
+ ApiConnectionError
11
+ ].each { |error_klass_name| const_set error_klass_name, Class.new(PhaxioError) }
12
+ end
13
+ end