sms-pilot-api-v1 0.0.3 → 0.0.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c7152ee4bb497bc839d159e8cdc7bb9b9b5735179a8c5ced0176924acd53727
4
- data.tar.gz: 9dfa498a10e6b68c6115ed42ff4a6b678a18b4b31ad2532f1092095d9efe9a60
3
+ metadata.gz: ef5f991fb1af59f48bbc7ccab3e1ab3b417c76fc22a584922fa5bca8879e294c
4
+ data.tar.gz: 83031cf779a24ed4b1d44de6d08f33ef611a0b9fdc63742c14ec792080c54fa5
5
5
  SHA512:
6
- metadata.gz: fb942ccb1bfab86c399c1c0567885d8ca0b43ca54f3e832d6316d6ad2838beb7d1ade363f537247aff90aa8090886a78f2ac0187c9e82c077ade0944bb4e5497
7
- data.tar.gz: 6ca91958e3d50371b7a48c7679b6a6285f6ff9d8389e2e2a0605e02f6eea85359e2b873366351d762fe48bad1bf288c3f9d94244fa8c0ac5a09a1c85230ae5de
6
+ metadata.gz: 84a60a7e124256682fd89d4d411c7402feb6597b0541493c2bd08b88b95a515cdf4ae9c0fb435939d7b6f98a56b2d9dd513cd344023bb2f446fbcffc8507eac0
7
+ data.tar.gz: d0a91bb376ef6090356040cc8eddca2272ce1917e044a7a7cea43f6fe812d265ea1c548eb63e95b5c163a1baed78758bb35a5a0075dea096674bbd4649f0a4ab
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
+ .DS_Storage
2
+ .rspec_status
1
3
  /.bundle/
2
4
  /.yardoc
3
5
  /_yardoc/
@@ -6,6 +8,3 @@
6
8
  /pkg/
7
9
  /spec/reports/
8
10
  /tmp/
9
-
10
- # rspec failure tracking
11
- .rspec_status
data/.yardopts ADDED
@@ -0,0 +1,8 @@
1
+ --private
2
+ --protected
3
+ -m markdown
4
+ -M redcarpet
5
+ -
6
+ lib/**/*.rb
7
+ CHANGELOG.md
8
+ README.md
data/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
- ## [Unreleased]
1
+ # Changelog
2
2
 
3
- ## [0.1.0] - 2021-05-06
3
+ ## [0.0.6] - 9 May 2021
4
+
5
+ - Corrects cost type
6
+ - Switches to PRY in console
7
+
8
+ ## [0.0.5] - 9 May 2021
9
+
10
+ - Adds locale support (RU / EN)
11
+
12
+ ## [0.0.4] - 9 May 2021
13
+
14
+ - Drop dependence on HTTP.rb gem
15
+ - Corrects what `#send_sms` returns (could return String errors instead of Booleans)
16
+ - Adds extensive [documentation](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot/Client) via YARD & RubyDoc
17
+
18
+ ## [0.0.3] - 6 May 2021
4
19
 
5
20
  - 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,32 +1,17 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sms-pilot-api-v1 (0.1.0)
5
- http (>= 4.4)
4
+ sms-pilot-api-v1 (0.0.5)
6
5
 
7
6
  GEM
8
7
  remote: https://rubygems.org/
9
8
  specs:
10
- addressable (2.7.0)
11
- public_suffix (>= 2.0.2, < 5.0)
9
+ coderay (1.1.3)
12
10
  diff-lcs (1.4.4)
13
- domain_name (0.5.20190701)
14
- unf (>= 0.0.5, < 1.0.0)
15
- ffi (1.15.0)
16
- ffi-compiler (1.0.1)
17
- ffi (>= 1.0.0)
18
- rake
19
- http (4.4.1)
20
- addressable (~> 2.3)
21
- http-cookie (~> 1.0)
22
- http-form_data (~> 2.2)
23
- http-parser (~> 1.2.0)
24
- http-cookie (1.0.3)
25
- domain_name (~> 0.5)
26
- http-form_data (2.3.0)
27
- http-parser (1.2.3)
28
- ffi-compiler (>= 1.0, < 2.0)
29
- public_suffix (4.0.6)
11
+ method_source (1.0.0)
12
+ pry (0.14.1)
13
+ coderay (~> 1.1)
14
+ method_source (~> 1.0)
30
15
  rake (13.0.3)
31
16
  rspec (3.10.0)
32
17
  rspec-core (~> 3.10.0)
@@ -41,14 +26,12 @@ GEM
41
26
  diff-lcs (>= 1.2.0, < 2.0)
42
27
  rspec-support (~> 3.10.0)
43
28
  rspec-support (3.10.2)
44
- unf (0.1.4)
45
- unf_ext
46
- unf_ext (0.0.7.7)
47
29
 
48
30
  PLATFORMS
49
31
  x86_64-darwin-17
50
32
 
51
33
  DEPENDENCIES
34
+ pry
52
35
  rake (~> 13.0)
53
36
  rspec (~> 3.0)
54
37
  sms-pilot-api-v1!
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # SmsPilot API v1 client
2
2
 
3
- Обёртка отправки GET-запроса на API endpoint сервиса SMS Pilot (API v1) для удобства доступа к ошибкам, статусам, цене SMS и т. п.
3
+ [![Gem Version](https://badge.fury.io/rb/sms-pilot-api-v1.svg)](https://badge.fury.io/rb/sms-pilot-api-v1)
4
+
5
+ Simple wrapper around SMS pilot API v1. Version 1 because it returns more data within its standard response.
4
6
 
5
7
  ## Installation
6
8
 
@@ -16,7 +18,7 @@ from GitHub:
16
18
  gem "sms-pilot-api-v1", git: "https://github.com/sergeypedan/sms-pilot-api-v1.git"
17
19
  ```
18
20
 
19
- ## Usage
21
+ ## Playground
20
22
 
21
23
  Test sending SMS from console with a test API key (find it at the end of this page):
22
24
 
@@ -25,11 +27,18 @@ cd $(bundle info sms-pilot-api-v1 --path)
25
27
  bin/console
26
28
  ```
27
29
 
30
+
31
+ ## Usage
32
+
28
33
  ### Initialize
29
34
 
30
35
  ```ruby
31
- client = SmsPilot::Client.new(api_key: "XXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZXXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZ")
32
- #<SmsPilot::Client:0x00007fb1c602d490 @api_key="XXXXX...", @error=nil, @response_status=nil, @response_headers=nil, @response_body=nil, @response_data={}, @url=nil>
36
+ require "sms_pilot"
37
+
38
+ key = "XXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZXXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZ"
39
+
40
+ client = SmsPilot::Client.new(api_key: key)
41
+ client = SmsPilot::Client.new(api_key: key, locale: :en) # Available locales are [:en, :ru]
33
42
  ```
34
43
 
35
44
  ### Before sending
@@ -42,7 +51,7 @@ client.phone # => nil
42
51
  client.rejected? # => false
43
52
  client.response_body # => nil
44
53
  client.response_data # => {}
45
- client.response_headers # => nil
54
+ client.response_headers # => {}
46
55
  client.response_status # => nil
47
56
  client.sender_blocked? # => false
48
57
  client.sms_cost # => nil
@@ -54,7 +63,8 @@ client.url # => nil
54
63
  ### Sending SMS
55
64
 
56
65
  ```ruby
57
- client.send_sms("+7 (902) 123-45-67", "Привет, мир!") # => true
66
+ client.send_sms("+7 (902) 123-45-67", "Привет, мир!")
67
+ # => true
58
68
  ```
59
69
 
60
70
  Returns result of `sms_sent?`, so it’s either `true` or `false`.
@@ -140,10 +150,11 @@ SMS sent:
140
150
 
141
151
  ```json
142
152
  {
153
+ "balance": "11908.50",
154
+ "cost": "1.68",
143
155
  "send": [
144
156
  { "server_id": "10000", "phone": "79021234567", "price": "1.68", "status": "0" }
145
- ],
146
- "balance": "11908.50", "cost": "1.68"
157
+ ]
147
158
  }
148
159
  ```
149
160
 
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
@@ -3,4 +3,3 @@
3
3
  require_relative "sms_pilot/version"
4
4
  require_relative "sms_pilot/errors"
5
5
  require_relative "sms_pilot/client"
6
-
@@ -1,16 +1,97 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "http"
3
+ require "json"
4
+ require "net/https"
4
5
  require "uri"
5
6
 
6
7
  module SmsPilot
7
8
 
8
- API_ENDPOINT = "https://smspilot.ru/api.php".freeze
9
-
9
+ # @!attribute [r] api_key
10
+ # @return [String] Your API key
11
+ #
12
+ # @!attribute [r] error
13
+ # Error message returned from the API, combined with the error code
14
+ # @example
15
+ # client.error #=> "Пользователь временно блокирован (спорная ситуация) (error code: 122)"
16
+ # @return [nil, String]
17
+ # @see #error_code
18
+ # @see #error_description
19
+ #
20
+ # @!attribute [r] locale
21
+ # @return [Symbol] Chosen locale (affects only the language of errors)
22
+ #
23
+ # @!attribute [r] phone
24
+ # @return [nil, String] phone after normalization
25
+ #
26
+ # @!attribute [r] response_body
27
+ # Response format is JSON (because we request it that way in {#build_uri}.
28
+ # @example
29
+ # "{\"send\":[{\"server_id\":\"10000\",\"phone\":\"79021234567\",\"price\":\"1.68\",\"status\":\"0\"}],\"balance\":\"20006.97\",\"cost\":\"1.68\"}"
30
+ # @return [nil, String] Unmodified HTTP resonse body that API returned
31
+ # @see #response_data
32
+ # @see #response_headers
33
+ # @see #response_status
34
+ #
35
+ # @!attribute [r] response_data
36
+ # Parsed <tt>@response_body</tt>. May be an empty <tt>Hash</tt> if parsing fails.
37
+ # @example
38
+ # {
39
+ # "balance" => "20006.97",
40
+ # "cost" => "1.68",
41
+ # "send" => [
42
+ # {
43
+ # "phone" => "79021234567",
44
+ # "price" => "1.68",
45
+ # "server_id" => "10000",
46
+ # "status" => "0"
47
+ # }
48
+ # ]
49
+ # }
50
+ # @return [Hash]
51
+ # @see #response_body
52
+ # @see #response_headers
53
+ # @see #response_status
54
+ #
55
+ # @!attribute [r] response_headers
56
+ # @example
57
+ # {
58
+ # "Access-Control-Allow-Origin" => "*",
59
+ # "Connection" => "close",
60
+ # "Content-Length" => "179",
61
+ # "Content-Type" => "application/json; charset=utf-8",
62
+ # "Date" => "Thu, 06 May 2021 04:52:58 GMT",
63
+ # "Server" => "nginx"
64
+ # }
65
+ # @return [nil, String] Unmodified HTTP resonse headers that API returned.
66
+ # @see #response_body
67
+ # @see #response_data
68
+ # @see #response_status
69
+ #
70
+ # @!attribute [r] response_status
71
+ # HTTP status of the request to the API. 200 in case of success.
72
+ # @example
73
+ # client.response_status #=> 200
74
+ #
75
+ # @return [nil, Integer]
76
+ # @see #response_body
77
+ # @see #response_data
78
+ # @see #response_headers
79
+ #
80
+ # @!attribute [r] url
81
+ # @example
82
+ # client.url #=> "https://smspilot.ru/api.php?api_key=XXX&format=json&send=TEXT&to=79021234567"
83
+ # @return [String] URL generated by combining <tt>API_ENDPOINT</tt>, your API key, SMS text & phone
84
+ #
10
85
  class Client
11
86
 
87
+ # Check current API endpoint URL at {https://smspilot.ru/apikey.php#api1}
88
+ #
89
+ API_ENDPOINT = "https://smspilot.ru/api.php".freeze
90
+ AVAILABLE_LOCALES = [:ru, :en].freeze
91
+
12
92
  attr_reader :api_key
13
93
  attr_reader :error
94
+ attr_reader :locale
14
95
  attr_reader :phone
15
96
  attr_reader :response_body
16
97
  attr_reader :response_data
@@ -19,128 +100,312 @@ module SmsPilot
19
100
  attr_reader :url
20
101
 
21
102
 
22
- def initialize(api_key:)
23
- fail TypeError, "API key must be a String, you pass a #{api_key.class} (#{api_key})" unless api_key.is_a? String
24
- fail TypeError, "API key cannot be empty" if api_key == ""
25
-
26
- @api_key = api_key
103
+ # @param api_key [String]
104
+ # @param locale [Symbol]
105
+ #
106
+ # @return [SmsPilot::Client]
107
+ # @raise [SmsPilot::InvalidAPIkeyError] if you pass anything but a non-empty String
108
+ # @raise [SmsPilot::InvalidLocaleError] if you pass anything but <tt>:ru</tt> or <tt>:en</tt>
109
+ #
110
+ # @see https://smspilot.ru/my-settings.php Get your production API key here
111
+ # @see https://smspilot.ru/apikey.php Get your development API key here
112
+ # @note Current development API key is <tt>"XXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZXXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZ"</tt>
113
+ #
114
+ # @example
115
+ # client = SmsPilot::Client.new(api_key: ENV["SMS_PILOT_API_KEY"])
116
+ # client = SmsPilot::Client.new(api_key: ENV["SMS_PILOT_API_KEY"], locale: :en)
117
+ #
118
+ def initialize(api_key:, locale: AVAILABLE_LOCALES[0])
119
+ @api_key = validate_api_key!(api_key)
27
120
  @error = nil
121
+ @locale = validate_locale!(locale)
28
122
  @response_status = nil
29
- @response_headers = nil
123
+ @response_headers = {}
30
124
  @response_body = nil
31
125
  @response_data = {}
32
126
  @url = nil
33
127
  end
34
128
 
35
- def send_sms(phone, text)
36
- fail TypeError, "`phone` must be a String, you pass a #{phone.class} (#{phone})" unless phone.is_a? String
37
- fail TypeError, "`text` must be a String, you pass a #{ text.class} (#{ text})" unless text.is_a? String
38
- fail ArgumentError, "`phone` cannot be empty" if phone == ""
39
- fail ArgumentError, "`text` cannot be empty" if text == ""
40
- fail ArgumentError, "`phone` must contain digits" if phone.scan(/\d/).none?
129
+
130
+ # @!group Main
131
+
132
+ # Send HTTP request to the API to ask them to transmit your SMS
133
+ #
134
+ # @return [Boolean] <tt>true</tt> if the SMS has been sent, <tt>false</tt> otherwise
135
+ #
136
+ # @param [String] phone The phone to send the SMS to. In free-form, will be sanitized.
137
+ # @param [String] message The text of your message.
138
+ #
139
+ # @raise [SmsPilot::InvalidPhoneError] if you pass anythig but a String with the <tt>phone</tt> argument
140
+ # @raise [SmsPilot::InvalidMessageError] if you pass anythig but a String with the <tt>message</tt> argument
141
+ # @raise [SmsPilot::InvalidMessageError] if your message is empty
142
+ # @raise [SmsPilot::InvalidPhoneError] if your phone is empty
143
+ # @raise [SmsPilot::InvalidPhoneError] if your phone has no digits
144
+ #
145
+ # @example
146
+ # client.send_sms("+7 (902) 123-45-67", "Привет, мир!") # => true
147
+ #
148
+ def send_sms(phone, message)
149
+ validate_phone! phone
150
+ validate_message! message
41
151
 
42
152
  @phone = normalize_phone(phone)
43
- @url = build_url(@phone, text)
153
+ uri = build_uri(@phone, message)
154
+ @url = uri.to_s
155
+
156
+ response = Net::HTTP.get_response(uri)
44
157
 
45
- response = HTTP.timeout(connect: 15, read: 30).accept(:json).get(@url)
46
- @response_status = response.status.code
47
- @response_headers = response.headers.to_h
48
- @response_body = response.body.to_s
158
+ @response_body = response.body
159
+ @response_status = response.code.to_i
160
+ @response_headers = response.each_capitalized.to_h
49
161
 
50
- unless response.status.success?
51
- @error = "HTTP request failed with code #{response.status.code}"
162
+ unless response.is_a?(Net::HTTPSuccess)
163
+ @error = "HTTP request failed with code #{response.code}"
52
164
  return false
53
165
  end
54
166
 
55
167
  @response_data = JSON.parse @response_body
56
168
 
57
- return @error = "#{error_description} (код ошибки: #{error_code})" if rejected?
169
+ if rejected?
170
+ @error = "#{error_description} (error code: #{error_code})"
171
+ return false
172
+ end
173
+
58
174
  return true
59
175
 
60
176
  rescue JSON::ParserError => error
61
177
  @error = "API returned invalid JSON. #{error.message}"
178
+ return false
62
179
 
63
- rescue HTTP::Error => error
64
- @error = error.message
65
-
66
- rescue => error
180
+ rescue SocketError, EOFError, IOError, SystemCallError,
181
+ Timeout::Error, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError,
182
+ Net::ProtocolError, OpenSSL::SSL::SSLError => error
67
183
  @error = error.message
184
+ return false
68
185
  end
69
186
 
187
+ # @!endgroup
188
+
189
+
190
+ # @!group State accessors
70
191
 
192
+ # Your current balance, remaining after sending that latest SMS.
193
+ #
194
+ # @return [nil, Float] Always <tt>nil</tt> before you send SMS and if the SMS was not sent, always Float after successfull SMS transmission.
195
+ # @example
196
+ # client.balance #=> 20215.25
197
+ #
71
198
  def balance
72
199
  @response_data["balance"]&.to_f if sms_sent?
73
200
  end
74
201
 
75
202
 
76
- # Коды ошибок: https://smspilot.ru/apikey.php#err
77
- # Расшифровка ошибки пишется в @error
203
+ # Numerical code of the error that occured when sending the SMS. In the range from 0 to 715 (which may change).
204
+ #
205
+ # @return [nil, Integer] <tt>nil</tt> is returned before sending SMS. Otherwise <tt>Integer</tt>
206
+ # @example
207
+ # client.error_code #=> 122
208
+ # @see #error
209
+ # @see #error_description
210
+ # @see https://smspilot.ru/apikey.php#err Error codes at the API documentation website
78
211
  #
79
212
  def error_code
80
213
  @response_data.dig("error", "code")&.to_i if rejected?
81
214
  end
82
215
 
83
216
 
84
- # Коды ошибок: https://smspilot.ru/apikey.php#err
85
- # Расшифровка ошибки пишется в @error
217
+ # Description of the error that occured when sending the SMS
218
+ #
219
+ # @return [nil, String] <tt>nil</tt> is returned before sending SMS. Otherwise <tt>String</tt>
220
+ # @example
221
+ # client.error_description #=> "Пользователь временно блокирован (спорная ситуация)"
222
+ # @see #error
223
+ # @see #error_code
224
+ # @see https://smspilot.ru/apikey.php#err Error codes at the API documentation website
86
225
  #
87
226
  def error_description
88
- @response_data.dig("error", "description_ru") if rejected?
227
+ method_name = (@locale == :ru) ? "description_ru" : "description"
228
+ @response_data.dig("error", method_name) if rejected?
89
229
  end
90
230
 
91
231
 
92
- # HTTP запрос удался, но API отказался отправлять SMS
232
+ # Did the API reject your request to send that SMS
233
+ #
234
+ # @return [Boolean] <tt>false</tt> is returned before sending SMS. Otherwise the <tt>Boolean</tt> corresponds to whether your request to send an SMS was rejected.
235
+ # @example
236
+ # client.rejected? #=> false
237
+ #
93
238
  def rejected?
94
239
  return false if sms_sent?
95
240
  @response_data["error"].is_a? Hash
96
241
  end
97
242
 
98
243
 
99
- # API сообщает, что мы заблокированы
244
+ # Did the API block you
100
245
  #
101
- # 105 из-за низкого баланса
102
- # 106 за спам/ошибки
103
- # 107 за недостоверные учетные данные / недоступна эл. почта / проблемы с телефоном
104
- # 122 спорная ситуация
246
+ # Error code | Description
247
+ # :---|:------------------
248
+ # 105 | из-за низкого баланса
249
+ # 106 | за спам/ошибки
250
+ # 107 | за недостоверные учетные данные / недоступна эл. почта / проблемы с телефоном
251
+ # 122 | спорная ситуация
105
252
  #
106
- # Расшифровка ошибки пишется в @error
253
+ # @return [Boolean] <tt>nil</tt> is returned before sending SMS. Otherwise the <tt>Boolean</tt> corresponds to whether the API has blocked you.
254
+ # @example
255
+ # client.sender_blocked? #=> false
256
+ # @see #error
257
+ # @see https://smspilot.ru/apikey.php#err Error codes at the API documentation website
107
258
  #
108
259
  def sender_blocked?
109
260
  [105, 106, 107, 122].include? error_code
110
261
  end
111
262
 
112
263
 
113
- # Цена отправленной только что SMS
264
+ # The cost of the SMS that has just been sent, in RUB
265
+ #
266
+ # @return [nil, Float]
267
+ # @example
268
+ # client.sms_cost #=> 2.63
269
+ #
114
270
  def sms_cost
115
- @response_data["cost"] if sms_sent?
271
+ @response_data["cost"]&.to_f if sms_sent?
116
272
  end
117
273
 
118
274
 
119
- # API успешно отправил SMS
275
+ # Has the SMS transmission been a success.
276
+ #
277
+ # @return [Boolean] <tt>nil</tt> is returned before sending SMS. Otherwise the <tt>Boolean</tt> corresponds to the result of SMS transmission.
278
+ # @see #sms_status
279
+ # @see #rejected?
280
+ # @see #error
281
+ #
282
+ # @example
283
+ # client.sms_sent? #=> true
284
+ #
120
285
  def sms_sent?
121
286
  @response_data["send"] != nil
122
287
  end
123
288
 
124
289
 
125
- # Статус доставки SMS
126
- # https://smspilot.ru/apikey.php#status
290
+ # SMS delivery status, as returned by the API
291
+ #
292
+ # @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.
293
+ # @see https://smspilot.ru/apikey.php#status List of available statuses at API documentation website
294
+ #
295
+ # Code | Name | Final? | Description
296
+ # ----:|:--------------|:-------|:-------------
297
+ # -2 | Ошибка | Да | Ошибка, неправильные параметры запроса
298
+ # -1 | Не доставлено | Да | Сообщение не доставлено (не в сети, заблокирован, не взял трубку), PING — не в сети, HLR — не обслуживается (заблокирован)
299
+ # 0 | Новое | Нет | Новое сообщение/запрос, ожидает обработки у нас на сервере
300
+ # 1 | В очереди | Нет | Сообщение или запрос ожидают отправки на сервере оператора
301
+ # 2 | Доставлено | Да | Доставлено, звонок совершен, PING — в сети, HLR — обслуживается
302
+ # 3 | Отложено | Нет | Отложенная отправка, отправка сообщения/запроса запланирована на другое время
303
+ #
304
+ # @example
305
+ # client.sms_status #=> 2
127
306
  #
128
307
  def sms_status
129
308
  @response_data.dig("send", 0, "status")&.to_i if sms_sent?
130
309
  end
131
310
 
311
+ # @!endgroup
132
312
 
133
- private
134
313
 
135
- def build_url(phone, text)
136
- URI.parse(API_ENDPOINT).tap do |url|
137
- url.query = URI.encode_www_form({ apikey: @api_key, format: :json, send: text, to: phone })
138
- end.to_s
314
+ # The URI we will send an HTTP request to
315
+ #
316
+ # @private
317
+ # @return [URI]
318
+ # @raise [URI::InvalidURIError] but is very unlikely because we provide the URL ourselves
319
+ #
320
+ # @example
321
+ # build_uri("79021234567", "Hello, World!")
322
+ # #=> #<URI::HTTPS https://smspilot.ru/api.php?apikey=XXX…&format=json&send=Hello%2C+World%21&to=79021234567>
323
+ #
324
+ private def build_uri(phone, text)
325
+ URI.parse(API_ENDPOINT).tap do |uri|
326
+ uri.query = URI.encode_www_form({ apikey: @api_key, format: :json, send: text, to: phone })
327
+ end
139
328
  end
140
329
 
141
- def normalize_phone(phone)
330
+
331
+ # Cleans up your phone from anything but digits. Also replaces 8 to 7 if it is the first digit.
332
+ #
333
+ # @private
334
+ # @return [String]
335
+ #
336
+ # @example
337
+ # normalize_phone("8 (902) 123-45-67") #=> 79021234567
338
+ # normalize_phone("+7-902-123-45-67") #=> 79021234567
339
+ #
340
+ private def normalize_phone(phone)
142
341
  phone.gsub(/[^0-9]/, '').sub(/^8/, '7').gsub('+7', '8')
143
342
  end
144
343
 
344
+
345
+ # @!group Validations
346
+
347
+ # Validates api_key
348
+ #
349
+ # @private
350
+ # @return [String] the original value passed into the method, only if it was valid
351
+ # @param [String] api_key
352
+
353
+ # @raise [SmsPilot::InvalidError] if api_key is not a String
354
+ # @raise [SmsPilot::InvalidError] if api_key is an empty String
355
+ #
356
+ private def validate_api_key!(api_key)
357
+ fail SmsPilot::InvalidAPIkeyError, "API key must be a String, you pass a #{api_key.class} (#{api_key})" unless api_key.is_a? String
358
+ fail SmsPilot::InvalidAPIkeyError, "API key cannot be empty" if api_key == ""
359
+ return api_key
360
+ end
361
+
362
+
363
+ # Validates locale
364
+ #
365
+ # @private
366
+ # @return [Symbol] the original value passed into the method, only if it was valid
367
+ # @param [Symbol] locale
368
+
369
+ # @raise [SmsPilot::InvalidError] if locale is not a Symbol
370
+ # @raise [SmsPilot::InvalidError] if locale is unrecognized
371
+ #
372
+ private def validate_locale!(locale)
373
+ fail SmsPilot::InvalidLocaleError, "locale must be a Symbol" unless locale.is_a? Symbol
374
+ fail SmsPilot::InvalidLocaleError, "API does not support locale :#{locale}; choose one of #{AVAILABLE_LOCALES.inspect}" unless AVAILABLE_LOCALES.include? locale
375
+ return locale
376
+ end
377
+
378
+
379
+ # Validates message
380
+ #
381
+ # @private
382
+ # @return [nil]
383
+ #
384
+ # @raise [SmsPilot::InvalidMessageError] if you pass anythig but a String with the <tt>message</tt> argument
385
+ # @raise [SmsPilot::InvalidMessageError] if your message is empty
386
+ #
387
+ private def validate_message!(message)
388
+ fail SmsPilot::InvalidMessageError, "SMS message must be a String, you pass a #{ message.class} (#{ message})" unless message.is_a? String
389
+ fail SmsPilot::InvalidMessageError, "SMS message cannot be empty" if message == ""
390
+ end
391
+
392
+
393
+ # Validates phone
394
+ #
395
+ # @private
396
+ # @return [nil]
397
+ #
398
+ # @raise [SmsPilot::InvalidPhoneError] if you pass anythig but a String with the <tt>phone</tt> argument
399
+ # @raise [SmsPilot::InvalidPhoneError] if your phone is empty
400
+ # @raise [SmsPilot::InvalidPhoneError] if your phone has no digits
401
+ #
402
+ private def validate_phone!(phone)
403
+ fail SmsPilot::InvalidPhoneError, "phone must be a String, you pass a #{phone.class} (#{phone})" unless phone.is_a? String
404
+ fail SmsPilot::InvalidPhoneError, "phone cannot be empty" if phone == ""
405
+ fail SmsPilot::InvalidPhoneError, "phone must contain digits" if phone.scan(/\d/).none?
406
+ end
407
+
408
+ # @!endgroup
409
+
145
410
  end
146
411
  end
@@ -1,5 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SmsPilot
4
- class Error < StandardError; end
4
+
5
+ class InvalidAPIkeyError < ArgumentError; end
6
+ class InvalidMessageError < ArgumentError; end
7
+ class InvalidPhoneError < ArgumentError; end
8
+ class InvalidLocaleError < ArgumentError; end
9
+
5
10
  end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SmsPilot
4
- VERSION = "0.0.3"
4
+
5
+ # Gem version
6
+ VERSION = "0.0.6"
7
+
5
8
  end
@@ -3,20 +3,20 @@
3
3
  require_relative "lib/sms_pilot/version"
4
4
 
5
5
  Gem::Specification.new do |spec|
6
+ spec.name = "sms-pilot-api-v1"
6
7
  spec.authors = ["Sergey Pedan"]
7
8
  spec.summary = "Simple wrapper around SMS pilot API v1"
8
9
  spec.description = "#{spec.summary}. Version 1 because it returns more data within its standard response"
9
10
  spec.email = ["sergey.pedan@gmail.com"]
10
- spec.homepage = "https://github.com/sergeypedan/sms-pilot-api-v1"
11
+ spec.homepage = "https://github.com/sergeypedan/#{spec.name}"
11
12
  spec.license = "MIT"
12
- spec.name = "sms-pilot-api-v1"
13
13
  spec.version = SmsPilot::VERSION
14
14
 
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",
19
- "documentation_uri" => "#{spec.homepage}#usage",
18
+ "changelog_uri" => "#{spec.homepage}/blob/master/CHANGELOG.md",
19
+ "documentation_uri" => "https://rubydoc.info/github/sergeypedan/#{spec.name}/master/",
20
20
  "homepage_uri" => spec.homepage,
21
21
  "source_code_uri" => spec.homepage
22
22
  }
@@ -24,12 +24,10 @@ Gem::Specification.new do |spec|
24
24
  # Specify which files should be added to the gem when it is released.
25
25
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
26
26
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
27
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
27
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features|pkg|doc)/}) }
28
28
  end
29
29
 
30
30
  spec.bindir = "bin"
31
31
  spec.require_paths = ["lib"]
32
32
 
33
- spec.add_runtime_dependency "http", "~> 4"
34
-
35
33
  end
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sms-pilot-api-v1
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergey Pedan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-06 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: http
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '4'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '4'
11
+ date: 2021-05-08 00:00:00.000000000 Z
12
+ dependencies: []
27
13
  description: Simple wrapper around SMS pilot API v1. Version 1 because it returns
28
14
  more data within its standard response
29
15
  email:
@@ -34,6 +20,7 @@ extra_rdoc_files: []
34
20
  files:
35
21
  - ".gitignore"
36
22
  - ".rspec"
23
+ - ".yardopts"
37
24
  - CHANGELOG.md
38
25
  - Gemfile
39
26
  - Gemfile.lock
@@ -45,14 +32,13 @@ files:
45
32
  - lib/sms_pilot/client.rb
46
33
  - lib/sms_pilot/errors.rb
47
34
  - lib/sms_pilot/version.rb
48
- - sms-pilot-api-v1-0.0.2.gem
49
35
  - sms-pilot-api-v1.gemspec
50
36
  homepage: https://github.com/sergeypedan/sms-pilot-api-v1
51
37
  licenses:
52
38
  - MIT
53
39
  metadata:
54
- changelog_uri: https://github.com/sergeypedan/sms-pilot-api-v1/blob/master/Changelog.md
55
- documentation_uri: https://github.com/sergeypedan/sms-pilot-api-v1#usage
40
+ changelog_uri: https://github.com/sergeypedan/sms-pilot-api-v1/blob/master/CHANGELOG.md
41
+ documentation_uri: https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/
56
42
  homepage_uri: https://github.com/sergeypedan/sms-pilot-api-v1
57
43
  source_code_uri: https://github.com/sergeypedan/sms-pilot-api-v1
58
44
  post_install_message:
@@ -70,7 +56,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
70
56
  - !ruby/object:Gem::Version
71
57
  version: '0'
72
58
  requirements: []
73
- rubygems_version: 3.2.5
59
+ rubygems_version: 3.2.8
74
60
  signing_key:
75
61
  specification_version: 4
76
62
  summary: Simple wrapper around SMS pilot API v1
Binary file