sms-pilot-api-v1 0.0.4 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1438f40054c6f5347c861fddb4530b2f86f7321ef4998eba159c18e70db520c
4
- data.tar.gz: fccbb5e7fb2c505e5a8bd80cc9e1410db5673b71aa2ac6ffac0bf41a89610797
3
+ metadata.gz: 2cdf5eab949b7c36ae220eec407cd1afce5e9fb5df2b7c09c8b7e05327bc67f5
4
+ data.tar.gz: a001b60a5975b0ed50aa69b4f2b66e3d974e001cacf6af949a60617a234d6fe6
5
5
  SHA512:
6
- metadata.gz: 86070669bff561d19b18242c595acc0bfc22ea6607bead4456e74391671e143ee6f1e269b1d4cd989d751d3ffda4c68fd85144d331a7e0499a64d7c114e344be
7
- data.tar.gz: '028935012e1fd06b533aa264d8d46f0eb87ee245fc08fe5bad688c89ceb2db77610ae75caea32a3193145d0d442f4f2d32f31e1b218a6951ef78e49c6b40e558'
6
+ metadata.gz: 7d8a78e4d68cf605f974feb7c3068245609f1fc2a2765d479c0badf013c6b43fb3b9e3480c97039befc09a9f12208c0ef3d098395c79d86a948ba040f6176763
7
+ data.tar.gz: 02da8904baac9232c9d4c4e6587f4dc1814a20aec9c2558ba8240db2ef8b324af72553278fd818577a32bccfa63dea6bf98c48272047ae67533cdcd687e2de1c
data/CHANGELOG.md CHANGED
@@ -1,11 +1,41 @@
1
1
  # Changelog
2
2
 
3
- ## [0.0.4] - 2021-05-09
3
+ ## [0.0.9] - 10 May 2021
4
+
5
+ - Passes `charset` attribute to the API in [`#build_uri`](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot%2FClient:build_uri)
6
+ - Passes `lang` attribute to the API in [`#build_uri`](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot%2FClient:build_uri)
7
+ - Stores constant request params in constants
8
+ - Deprecates [`#sms_status`](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot%2FClient:sms_status) in favor of [`#broadcast_status`](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot%2FClient:broadcast_status)
9
+
10
+ ## [0.0.8] - 10 May 2021
11
+
12
+ - Adds [`#broadcast_id`](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot%2FClient:broadcast_id) method
13
+ - Adds [roadmap section](https://github.com/sergeypedan/sms-pilot-api-v1#roadmap) in the Readme
14
+
15
+ ## [0.0.7] - 9 May 2021
16
+
17
+ - Returns original values from validation methods
18
+ - Offloads parsing response body to a method
19
+ - Improves documentation
20
+ - Adds CodeClimate badges
21
+ - Writes tests for [`#initialize`](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot%2FClient:initialize)
22
+ - Writes tests for [`#api_key`](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot%2FClient:api_key)
23
+
24
+ ## [0.0.6] - 9 May 2021
25
+
26
+ - Corrects cost type
27
+ - Switches to PRY in console
28
+
29
+ ## [0.0.5] - 9 May 2021
30
+
31
+ - Adds locale support (RU / EN)
32
+
33
+ ## [0.0.4] - 9 May 2021
4
34
 
5
35
  - Drop dependence on HTTP.rb gem
6
- - Corrects what `#send_sms` returns (could return String errors instead of Booleans)
36
+ - Corrects what [`#send_sms`](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot%2FClient:send_sms) returns (could return String errors instead of Booleans)
7
37
  - Adds extensive [documentation](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot/Client) via YARD & RubyDoc
8
38
 
9
- ## [0.0.3] - 2021-05-06
39
+ ## [0.0.3] - 6 May 2021
10
40
 
11
41
  - Initial release
data/Gemfile CHANGED
@@ -5,5 +5,6 @@ source "https://rubygems.org"
5
5
  # Specify your gem's dependencies in gemspec
6
6
  gemspec
7
7
 
8
+ gem "pry"
8
9
  gem "rake", "~> 13.0"
9
10
  gem "rspec", "~> 3.0"
data/Gemfile.lock CHANGED
@@ -1,12 +1,17 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sms-pilot-api-v1 (0.0.3)
4
+ sms-pilot-api-v1 (0.0.9)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
+ coderay (1.1.3)
9
10
  diff-lcs (1.4.4)
11
+ method_source (1.0.0)
12
+ pry (0.14.1)
13
+ coderay (~> 1.1)
14
+ method_source (~> 1.0)
10
15
  rake (13.0.3)
11
16
  rspec (3.10.0)
12
17
  rspec-core (~> 3.10.0)
@@ -26,9 +31,10 @@ PLATFORMS
26
31
  x86_64-darwin-17
27
32
 
28
33
  DEPENDENCIES
34
+ pry
29
35
  rake (~> 13.0)
30
36
  rspec (~> 3.0)
31
37
  sms-pilot-api-v1!
32
38
 
33
39
  BUNDLED WITH
34
- 2.2.11
40
+ 2.2.17
data/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # SmsPilot API v1 client
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/sms-pilot-api-v1.svg)](https://badge.fury.io/rb/sms-pilot-api-v1)
4
+ [![Maintainability](https://api.codeclimate.com/v1/badges/42765c3098d5f531a3f7/maintainability)](https://codeclimate.com/github/sergeypedan/sms-pilot-api-v1/maintainability)
5
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/42765c3098d5f531a3f7/test_coverage)](https://codeclimate.com/github/sergeypedan/sms-pilot-api-v1/test_coverage)
6
+ [![Inch CI documentation](https://inch-ci.org/github/sergeypedan/sms-pilot-api-v1.svg?branch=master&style=flat)](https://inch-ci.org/github/sergeypedan/sms-pilot-api-v1)
4
7
 
5
8
  Simple wrapper around SMS pilot API v1. Version 1 because it returns more data within its standard response.
6
9
 
@@ -18,7 +21,7 @@ from GitHub:
18
21
  gem "sms-pilot-api-v1", git: "https://github.com/sergeypedan/sms-pilot-api-v1.git"
19
22
  ```
20
23
 
21
- ## Usage
24
+ ## Playground
22
25
 
23
26
  Test sending SMS from console with a test API key (find it at the end of this page):
24
27
 
@@ -27,20 +30,30 @@ cd $(bundle info sms-pilot-api-v1 --path)
27
30
  bin/console
28
31
  ```
29
32
 
33
+
34
+ ## Usage
35
+
30
36
  ### Initialize
31
37
 
32
38
  ```ruby
33
39
  require "sms_pilot"
34
40
 
35
- client = SmsPilot::Client.new(api_key: "XXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZXXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZ")
36
- #<SmsPilot::Client:0x00007fb1c602d490 @api_key="XXXXX...", @error=nil, @response_status=nil, @response_headers=nil, @response_body=nil, @response_data={}, @url=nil>
41
+ key = "XXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZXXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZ"
42
+
43
+ client = SmsPilot::Client.new(api_key: key)
44
+ client = SmsPilot::Client.new(api_key: key, locale: :en) # Available locales are [:en, :ru]
37
45
  ```
38
46
 
47
+ Method [documentation](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot/Client#initialize-instance_method) at RubyDoc.
48
+
39
49
  ### Before sending
40
50
 
51
+ There are a bunch of methods describing the state of affairs:
52
+
41
53
  ```ruby
42
54
  client.api_key # => "YOUR API KEY"
43
55
  client.balance # => nil
56
+ client.broadcast_id # => nil
44
57
  client.error # => nil
45
58
  client.phone # => nil
46
59
  client.rejected? # => false
@@ -55,20 +68,27 @@ client.sms_status # => nil
55
68
  client.url # => nil
56
69
  ```
57
70
 
71
+ before the request is sent they return obvious nils or empty structures; after the request they are populated with data.
72
+
73
+ See [structured documentation](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot/Client) for those methods at RubyDoc.
74
+
58
75
  ### Sending SMS
59
76
 
60
77
  ```ruby
61
- client.send_sms("+7 (902) 123-45-67", "Привет, мир!") # => true
78
+ client.send_sms("+7 (902) 123-45-67", "Привет, мир!")
79
+ # => true
62
80
  ```
63
81
 
64
82
  Returns result of `sms_sent?`, so it’s either `true` or `false`.
65
83
 
84
+ Method [documentation](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot/Client#send_sms-instance_method) at RubyDoc.
66
85
 
67
86
  ### Sending SMS succeeded
68
87
 
69
88
  ```ruby
70
89
  client.api_key # => "YOUR API KEY"
71
90
  client.balance # => 20006.97
91
+ client.broadcast_id # => 10000
72
92
  client.error # => nil
73
93
  client.phone # => "79021234567"
74
94
  client.rejected? # => false
@@ -88,6 +108,7 @@ client.url # => "https://smspilot.ru/api.php?apikey=1234567890&form
88
108
  ```ruby
89
109
  client.api_key # => "YOUR API KEY"
90
110
  client.balance # => nil
111
+ client.broadcast_id # => nil
91
112
  client.error # => "Неправильный API-ключ (см. настройки API в личном кабинете) (код ошибки: 101)"
92
113
  client.phone # => "79021234567"
93
114
  client.rejected? # => true
@@ -107,6 +128,7 @@ client.url # => "https://smspilot.ru/api.php?apikey=1234567890&form
107
128
  ```ruby
108
129
  client.api_key # => "YOUR API KEY"
109
130
  client.balance # => nil
131
+ client.broadcast_id # => nil
110
132
  client.error # => "HTTP request failed with code 404"
111
133
  client.phone # => "79021234567"
112
134
  client.rejected? # => false
@@ -124,9 +146,9 @@ client.url # => "https://smspilot.ru/api.php?apikey=1234567890&form
124
146
 
125
147
  ## SMS pilot API docs
126
148
 
127
- - [web version](https://smspilot.ru/apikey.php) — см. вкладку PHP, в остальных ничего нет
149
+ - [Web version](https://smspilot.ru/apikey.php) — см. вкладку PHP, в остальных ничего нет
128
150
  - [PDF version](https://smspilot.ru/download/SMSPilotRu-HTTP-v1.9.19.pdf) — тут намного подробнее
129
- - [Коды ошибок](https://smspilot.ru/apikey.php#err)
151
+ - [API error code](https://smspilot.ru/apikey.php#err)
130
152
 
131
153
 
132
154
  ## Test API key
@@ -163,3 +185,18 @@ SMS rejected:
163
185
  }
164
186
  }
165
187
  ```
188
+
189
+
190
+ ## Documentation
191
+
192
+ See [structured documentation](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot/Client) at RubyDoc.
193
+
194
+
195
+ ## Roadmap
196
+
197
+ 1. Switch to POST to escape 1024 symbolos GET request limit
198
+ 1. Support passing `sender` to the API
199
+ 1. Switch to result object pattern
200
+ 1. Проверка статусов SMS
201
+ 1. Проверка баланса
202
+ 1. Информация о пользователе
data/bin/console CHANGED
@@ -8,8 +8,5 @@ require "sms_pilot"
8
8
  # with your gem easier. You can also use a different console, if you like.
9
9
 
10
10
  # (If you use this, don't forget to add pry to your Gemfile!)
11
- # require "pry"
12
- # Pry.start
13
-
14
- require "irb"
15
- IRB.start(__FILE__)
11
+ require "pry"
12
+ Pry.start
data/lib/sms_pilot.rb CHANGED
@@ -1,6 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Module that for now encompasses only API client
4
+ #
5
+ module SmsPilot
6
+ end
7
+
3
8
  require_relative "sms_pilot/version"
4
9
  require_relative "sms_pilot/errors"
5
10
  require_relative "sms_pilot/client"
6
-
@@ -7,7 +7,9 @@ require "uri"
7
7
  module SmsPilot
8
8
 
9
9
  # @!attribute [r] api_key
10
- # @return [String] Your API key.
10
+ # @return [String] your API key
11
+ # @example
12
+ # client.api_key #=> "XXX..."
11
13
  #
12
14
  # @!attribute [r] error
13
15
  # Error message returned from the API, combined with the error code
@@ -17,8 +19,20 @@ module SmsPilot
17
19
  # @see #error_code
18
20
  # @see #error_description
19
21
  #
22
+ # @!attribute [r] locale
23
+ # Chosen locale (affects only the language of errors)
24
+ #
25
+ # @return [Symbol]
26
+ # @example
27
+ # client.locale #=> :ru
28
+ #
29
+ # @!attribute [r] phone
30
+ # @return [nil, String] phone after normalization
31
+ # @example
32
+ # client.phone #=> "79021234567"
33
+ #
20
34
  # @!attribute [r] response_body
21
- # Response format is JSON (because we request it that way in {#build_uri}.
35
+ # Response format is JSON (because we request it that way in {#build_uri}).
22
36
  # @example
23
37
  # "{\"send\":[{\"server_id\":\"10000\",\"phone\":\"79021234567\",\"price\":\"1.68\",\"status\":\"0\"}],\"balance\":\"20006.97\",\"cost\":\"1.68\"}"
24
38
  # @return [nil, String] Unmodified HTTP resonse body that API returned
@@ -26,28 +40,9 @@ module SmsPilot
26
40
  # @see #response_headers
27
41
  # @see #response_status
28
42
  #
29
- # @!attribute [r] response_data
30
- # Parsed <tt>@response_body</tt>. May be an empty <tt>Hash</tt> if parsing fails.
31
- # @example
32
- # {
33
- # "balance" => "20006.97",
34
- # "cost" => "1.68",
35
- # "send" => [
36
- # {
37
- # "phone" => "79021234567",
38
- # "price" => "1.68",
39
- # "server_id" => "10000",
40
- # "status" => "0"
41
- # }
42
- # ]
43
- # }
44
- # @return [Hash]
45
- # @see #response_body
46
- # @see #response_headers
47
- # @see #response_status
48
- #
49
43
  # @!attribute [r] response_headers
50
44
  # @example
45
+ # client.response_headers #=>
51
46
  # {
52
47
  # "Access-Control-Allow-Origin" => "*",
53
48
  # "Connection" => "close",
@@ -71,48 +66,50 @@ module SmsPilot
71
66
  # @see #response_data
72
67
  # @see #response_headers
73
68
  #
74
- # @!attribute [r] url
75
- # @example
76
- # client.url #=> "https://smspilot.ru/api.php?api_key=XXX&format=json&send=TEXT&to=79021234567"
77
- # @return [String] URL generated by combining <tt>API_ENDPOINT</tt>, your API key, SMS text & phone
78
- #
79
69
  class Client
80
70
 
81
71
  # Check current API endpoint URL at {https://smspilot.ru/apikey.php#api1}
82
72
  #
83
73
  API_ENDPOINT = "https://smspilot.ru/api.php".freeze
84
74
 
75
+ # Locale influences only the language of API errors
76
+ #
77
+ AVAILABLE_LOCALES = [:ru, :en].freeze
78
+
79
+ REQUEST_ACCEPT_FORMAT = "json".freeze
80
+ REQUEST_CHARSET = "utf-8".freeze
81
+
85
82
  attr_reader :api_key
86
83
  attr_reader :error
84
+ attr_reader :locale
87
85
  attr_reader :phone
88
86
  attr_reader :response_body
89
- attr_reader :response_data
90
87
  attr_reader :response_headers
91
88
  attr_reader :response_status
92
- attr_reader :url
93
89
 
94
90
 
95
91
  # @param api_key [String]
92
+ # @param locale [Symbol]
93
+ #
96
94
  # @return [SmsPilot::Client]
97
95
  # @raise [SmsPilot::InvalidAPIkeyError] if you pass anything but a non-empty String
96
+ # @raise [SmsPilot::InvalidLocaleError] if you pass anything but <tt>:ru</tt> or <tt>:en</tt>
97
+ #
98
98
  # @see https://smspilot.ru/my-settings.php Get your production API key here
99
99
  # @see https://smspilot.ru/apikey.php Get your development API key here
100
100
  # @note Current development API key is <tt>"XXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZXXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZ"</tt>
101
101
  #
102
102
  # @example
103
103
  # client = SmsPilot::Client.new(api_key: ENV["SMS_PILOT_API_KEY"])
104
+ # client = SmsPilot::Client.new(api_key: ENV["SMS_PILOT_API_KEY"], locale: :en)
104
105
  #
105
- def initialize(api_key:)
106
- fail SmsPilot::InvalidAPIkeyError, "API key must be a String, you pass a #{api_key.class} (#{api_key})" unless api_key.is_a? String
107
- fail SmsPilot::InvalidAPIkeyError, "API key cannot be empty" if api_key == ""
108
-
109
- @api_key = api_key
106
+ def initialize(api_key:, locale: AVAILABLE_LOCALES[0])
107
+ @api_key = validate_api_key!(api_key)
110
108
  @error = nil
109
+ @locale = validate_locale!(locale)
111
110
  @response_status = nil
112
111
  @response_headers = {}
113
112
  @response_body = nil
114
- @response_data = {}
115
- @url = nil
116
113
  end
117
114
 
118
115
 
@@ -130,6 +127,7 @@ module SmsPilot
130
127
  # @raise [SmsPilot::InvalidMessageError] if your message is empty
131
128
  # @raise [SmsPilot::InvalidPhoneError] if your phone is empty
132
129
  # @raise [SmsPilot::InvalidPhoneError] if your phone has no digits
130
+ # @raise [URI::InvalidURIError] but is almost impossible, because we provide the URL ourselves
133
131
  #
134
132
  # @example
135
133
  # client.send_sms("+7 (902) 123-45-67", "Привет, мир!") # => true
@@ -139,28 +137,14 @@ module SmsPilot
139
137
  validate_message! message
140
138
 
141
139
  @phone = normalize_phone(phone)
142
- uri = build_uri(@phone, message)
143
- @url = uri.to_s
140
+ @uri = build_uri(@phone, message)
144
141
 
145
- response = Net::HTTP.get_response(uri)
142
+ response = persist_response_details Net::HTTP.get_response(@uri)
146
143
 
147
- @response_body = response.body
148
- @response_status = response.code.to_i
149
- @response_headers = response.each_capitalized.to_h
144
+ @error = "HTTP request failed with code #{response.code}" and return false unless response.is_a?(Net::HTTPSuccess)
145
+ @error = "#{error_description} (error code: #{error_code})" and return false if rejected?
150
146
 
151
- unless response.is_a?(Net::HTTPSuccess)
152
- @error = "HTTP request failed with code #{response.code}"
153
- return false
154
- end
155
-
156
- @response_data = JSON.parse @response_body
157
-
158
- if rejected?
159
- @error = "#{error_description} (error code: #{error_code})"
160
- return false
161
- end
162
-
163
- return true
147
+ true
164
148
 
165
149
  rescue JSON::ParserError => error
166
150
  @error = "API returned invalid JSON. #{error.message}"
@@ -185,7 +169,45 @@ module SmsPilot
185
169
  # client.balance #=> 20215.25
186
170
  #
187
171
  def balance
188
- @response_data["balance"]&.to_f if sms_sent?
172
+ response_data["balance"]&.to_f if sms_sent?
173
+ end
174
+
175
+
176
+ # SMS broadcast ID (API documentation calls it “server ID” but it makes no sense, as it is clearly the ID of the transmission, not of a server)
177
+ #
178
+ # @example
179
+ # client.broadcast_id #=> 10000
180
+ #
181
+ # @return [nil, Integer]
182
+ #
183
+ # @see #response_data
184
+ #
185
+ def broadcast_id
186
+ @response_data.dig("send", 0, "server_id")&.to_i if sms_sent?
187
+ end
188
+
189
+
190
+ # SMS delivery status, as returned by the API
191
+ #
192
+ # @return [nil, Integer] <tt>nil</tt> is returned before sending SMS or if the request was rejected. Otherwise an <tt>Integer</tt> in the range of [-2..3] is returned.
193
+ # @see https://smspilot.ru/apikey.php#status List of available statuses at API documentation website
194
+ #
195
+ # Code | Name | Final? | Description
196
+ # ----:|:--------------|:-------|:-------------
197
+ # -2 | Ошибка | Да | Ошибка, неправильные параметры запроса
198
+ # -1 | Не доставлено | Да | Сообщение не доставлено (не в сети, заблокирован, не взял трубку), PING — не в сети, HLR — не обслуживается (заблокирован)
199
+ # 0 | Новое | Нет | Новое сообщение/запрос, ожидает обработки у нас на сервере
200
+ # 1 | В очереди | Нет | Сообщение или запрос ожидают отправки на сервере оператора
201
+ # 2 | Доставлено | Да | Доставлено, звонок совершен, PING — в сети, HLR — обслуживается
202
+ # 3 | Отложено | Нет | Отложенная отправка, отправка сообщения/запроса запланирована на другое время
203
+ #
204
+ # @example
205
+ # client.broadcast_status #=> 2
206
+ #
207
+ # @see #sms_status
208
+ #
209
+ def broadcast_status
210
+ @response_data.dig("send", 0, "status")&.to_i if sms_sent?
189
211
  end
190
212
 
191
213
 
@@ -213,7 +235,8 @@ module SmsPilot
213
235
  # @see https://smspilot.ru/apikey.php#err Error codes at the API documentation website
214
236
  #
215
237
  def error_description
216
- @response_data.dig("error", "description_ru") if rejected?
238
+ method_name = (@locale == :ru) ? "description_ru" : "description"
239
+ @response_data.dig("error", method_name) if rejected?
217
240
  end
218
241
 
219
242
 
@@ -225,7 +248,36 @@ module SmsPilot
225
248
  #
226
249
  def rejected?
227
250
  return false if sms_sent?
228
- @response_data["error"].is_a? Hash
251
+ response_data["error"].is_a? Hash
252
+ end
253
+
254
+
255
+ # Parses <tt>@response_body</tt> and memoizes result in <tt>@response_data</tt>
256
+ #
257
+ # @example
258
+ # {
259
+ # "balance" => "20006.97",
260
+ # "cost" => "1.68",
261
+ # "send" => [
262
+ # {
263
+ # "phone" => "79021234567",
264
+ # "price" => "1.68",
265
+ # "server_id" => "10000",
266
+ # "status" => "0"
267
+ # }
268
+ # ]
269
+ # }
270
+ #
271
+ # @return [Hash]
272
+ # @raise [JSON::ParserError] which is rescued in {#send_sms}
273
+ #
274
+ # @see #response_body
275
+ # @see #response_headers
276
+ # @see #response_status
277
+ #
278
+ def response_data
279
+ return {} unless @response_body
280
+ @response_data ||= JSON.parse @response_body
229
281
  end
230
282
 
231
283
 
@@ -256,7 +308,7 @@ module SmsPilot
256
308
  # client.sms_cost #=> 2.63
257
309
  #
258
310
  def sms_cost
259
- @response_data["cost"] if sms_sent?
311
+ response_data["cost"]&.to_f if sms_sent?
260
312
  end
261
313
 
262
314
 
@@ -271,54 +323,66 @@ module SmsPilot
271
323
  # client.sms_sent? #=> true
272
324
  #
273
325
  def sms_sent?
274
- @response_data["send"] != nil
326
+ response_data["send"] != nil
275
327
  end
276
328
 
277
329
 
278
- # SMS delivery status, as returned by the API
279
- #
280
- # @return [nil, Integer] <tt>nil</tt> is returned before sending SMS or if the request was rejected. Otherwise an <tt>Integer</tt> in the range of [-2..3] is returned.
281
- # @see https://smspilot.ru/apikey.php#status List of available statuses at API documentation website
330
+ # @deprecated (in favor of {#broadcast_status})
282
331
  #
283
- # Code | Name | Final? | Description
284
- # ----:|:--------------|:-------|:-------------
285
- # -2 | Ошибка | Да | Ошибка, неправильные параметры запроса
286
- # -1 | Не доставлено | Да | Сообщение не доставлено (не в сети, заблокирован, не взял трубку), PING — не в сети, HLR — не обслуживается (заблокирован)
287
- # 0 | Новое | Нет | Новое сообщение/запрос, ожидает обработки у нас на сервере
288
- # 1 | В очереди | Нет | Сообщение или запрос ожидают отправки на сервере оператора
289
- # 2 | Доставлено | Да | Доставлено, звонок совершен, PING — в сети, HLR — обслуживается
290
- # 3 | Отложено | Нет | Отложенная отправка, отправка сообщения/запроса запланирована на другое время
332
+ def sms_status
333
+ broadcast_status
334
+ end
335
+
336
+
337
+ # URL generated by combining <tt>API_ENDPOINT</tt>, your API key, SMS text & phone
291
338
  #
292
339
  # @example
293
- # client.sms_status #=> 2
340
+ # client.url #=> "https://smspilot.ru/api.php?api_key=XXX&format=json&send=TEXT&to=79021234567"
294
341
  #
295
- def sms_status
296
- @response_data.dig("send", 0, "status")&.to_i if sms_sent?
342
+ # @return [nil, String]
343
+ #
344
+ def url
345
+ @uri&.to_s
297
346
  end
298
347
 
299
348
  # @!endgroup
300
349
 
301
350
 
302
351
  # The URI we will send an HTTP request to
303
- #
304
352
  # @private
305
- # @return [URI]
306
- # @raise [URI::InvalidURIError] but is very unlikely because we provide the URL ourselves
307
353
  #
308
354
  # @example
309
355
  # build_uri("79021234567", "Hello, World!")
310
356
  # #=> #<URI::HTTPS https://smspilot.ru/api.php?apikey=XXX…&format=json&send=Hello%2C+World%21&to=79021234567>
311
357
  #
358
+ # @return [URI]
359
+ # @raise [URI::InvalidURIError] but is almost impossible, because we provide the URL ourselves
360
+ #
361
+ # @see #api_key
362
+ # @see #phone
363
+ # @see #validate_phone!
364
+ # @see #validate_message!
365
+ #
312
366
  private def build_uri(phone, text)
313
367
  URI.parse(API_ENDPOINT).tap do |uri|
314
- uri.query = URI.encode_www_form({ apikey: @api_key, format: :json, send: text, to: phone })
368
+ uri.query = URI.encode_www_form({
369
+ apikey: @api_key,
370
+ charset: REQUEST_CHARSET,
371
+ format: REQUEST_ACCEPT_FORMAT,
372
+ lang: @locale,
373
+ send: text,
374
+ to: phone
375
+ })
315
376
  end
316
377
  end
317
378
 
318
379
 
380
+
381
+
319
382
  # Cleans up your phone from anything but digits. Also replaces 8 to 7 if it is the first digit.
320
383
  #
321
384
  # @private
385
+ # @param [String] phone
322
386
  # @return [String]
323
387
  #
324
388
  # @example
@@ -330,26 +394,60 @@ module SmsPilot
330
394
  end
331
395
 
332
396
 
333
- # Validates phone
397
+ # Saves response details into instance variables
398
+ # @private
399
+ #
400
+ # @return [response]
401
+ # @raise [TypeError] unless a Net::HTTPResponse passed
402
+ #
403
+ private def persist_response_details(response)
404
+ fail TypeError, "Net::HTTPResponse expected, you pass a #{response.class}" unless response.is_a? Net::HTTPResponse
405
+ @response_body = response.body
406
+ @response_status = response.code.to_i
407
+ @response_headers = response.each_capitalized.to_h
408
+ response
409
+ end
334
410
 
411
+
412
+ # @!group Validations
413
+
414
+ # Validates api_key
415
+ #
335
416
  # @private
336
- # @return [nil]
417
+ # @return [String] the original value passed into the method, only if it was valid
418
+ # @param [String] api_key
337
419
  #
338
- # @raise [SmsPilot::InvalidPhoneError] if you pass anythig but a String with the <tt>phone</tt> argument
339
- # @raise [SmsPilot::InvalidPhoneError] if your phone is empty
340
- # @raise [SmsPilot::InvalidPhoneError] if your phone has no digits
420
+ # @raise [SmsPilot::InvalidError] if api_key is not a String
421
+ # @raise [SmsPilot::InvalidError] if api_key is an empty String
341
422
  #
342
- private def validate_phone!(phone)
343
- fail SmsPilot::InvalidPhoneError, "phone must be a String, you pass a #{phone.class} (#{phone})" unless phone.is_a? String
344
- fail SmsPilot::InvalidPhoneError, "phone cannot be empty" if phone == ""
345
- fail SmsPilot::InvalidPhoneError, "phone must contain digits" if phone.scan(/\d/).none?
423
+ private def validate_api_key!(api_key)
424
+ fail SmsPilot::InvalidAPIkeyError, "API key must be a String, you pass a #{api_key.class} (#{api_key})" unless api_key.is_a? String
425
+ fail SmsPilot::InvalidAPIkeyError, "API key cannot be empty" if api_key == ""
426
+ return api_key
346
427
  end
347
428
 
348
429
 
349
- # Validates message
430
+ # Validates locale
431
+ #
432
+ # @private
433
+ # @return [Symbol] the original value passed into the method, only if it was valid
434
+ # @param [Symbol] locale
435
+ #
436
+ # @raise [SmsPilot::InvalidError] if locale is not a Symbol
437
+ # @raise [SmsPilot::InvalidError] if locale is unrecognized
438
+ #
439
+ private def validate_locale!(locale)
440
+ fail SmsPilot::InvalidLocaleError, "locale must be a Symbol" unless locale.is_a? Symbol
441
+ fail SmsPilot::InvalidLocaleError, "API does not support locale :#{locale}; choose one of #{AVAILABLE_LOCALES.inspect}" unless AVAILABLE_LOCALES.include? locale
442
+ return locale
443
+ end
444
+
350
445
 
446
+ # Validates message
351
447
  # @private
352
- # @return [nil]
448
+ #
449
+ # @param [String] message
450
+ # @return [String] the original value passed into the method, only if it was valid
353
451
  #
354
452
  # @raise [SmsPilot::InvalidMessageError] if you pass anythig but a String with the <tt>message</tt> argument
355
453
  # @raise [SmsPilot::InvalidMessageError] if your message is empty
@@ -357,7 +455,28 @@ module SmsPilot
357
455
  private def validate_message!(message)
358
456
  fail SmsPilot::InvalidMessageError, "SMS message must be a String, you pass a #{ message.class} (#{ message})" unless message.is_a? String
359
457
  fail SmsPilot::InvalidMessageError, "SMS message cannot be empty" if message == ""
458
+ message
360
459
  end
361
460
 
461
+
462
+ # Validates phone
463
+ # @private
464
+ #
465
+ # @param [String] phone
466
+ # @return [String] the original value passed into the method, only if it was valid
467
+ #
468
+ # @raise [SmsPilot::InvalidPhoneError] if you pass anythig but a String with the <tt>phone</tt> argument
469
+ # @raise [SmsPilot::InvalidPhoneError] if your phone is empty
470
+ # @raise [SmsPilot::InvalidPhoneError] if your phone has no digits
471
+ #
472
+ private def validate_phone!(phone)
473
+ fail SmsPilot::InvalidPhoneError, "phone must be a String, you pass a #{phone.class} (#{phone})" unless phone.is_a? String
474
+ fail SmsPilot::InvalidPhoneError, "phone cannot be empty" if phone == ""
475
+ fail SmsPilot::InvalidPhoneError, "phone must contain digits" if phone.scan(/\d/).none?
476
+ phone
477
+ end
478
+
479
+ # @!endgroup
480
+
362
481
  end
363
482
  end
@@ -5,5 +5,6 @@ module SmsPilot
5
5
  class InvalidAPIkeyError < ArgumentError; end
6
6
  class InvalidMessageError < ArgumentError; end
7
7
  class InvalidPhoneError < ArgumentError; end
8
+ class InvalidLocaleError < ArgumentError; end
8
9
 
9
10
  end
@@ -3,6 +3,6 @@
3
3
  module SmsPilot
4
4
 
5
5
  # Gem version
6
- VERSION = "0.0.4"
6
+ VERSION = "0.0.9"
7
7
 
8
8
  end
@@ -15,10 +15,10 @@ Gem::Specification.new do |spec|
15
15
  spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
16
16
 
17
17
  spec.metadata = {
18
- "changelog_uri" => "#{spec.homepage}/blob/master/CHANGELOG.md",
18
+ "changelog_uri" => "#{spec.homepage}/blob/master/CHANGELOG.md",
19
19
  "documentation_uri" => "https://rubydoc.info/github/sergeypedan/#{spec.name}/master/",
20
- "homepage_uri" => spec.homepage,
21
- "source_code_uri" => spec.homepage
20
+ "homepage_uri" => spec.homepage,
21
+ "source_code_uri" => spec.homepage
22
22
  }
23
23
 
24
24
  # Specify which files should be added to the gem when it is released.
@@ -27,7 +27,10 @@ Gem::Specification.new do |spec|
27
27
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features|pkg|doc)/}) }
28
28
  end
29
29
 
30
- spec.bindir = "bin"
30
+ spec.bindir = "exe"
31
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
32
  spec.require_paths = ["lib"]
32
33
 
34
+ # spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
35
+
33
36
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sms-pilot-api-v1
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergey Pedan
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2021-05-08 00:00:00.000000000 Z
11
+ date: 2021-05-10 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Simple wrapper around SMS pilot API v1. Version 1 because it returns
14
14
  more data within its standard response