sms-pilot-api-v1 0.0.4 → 0.0.9

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: 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