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 +4 -4
- data/CHANGELOG.md +33 -3
- data/Gemfile +1 -0
- data/Gemfile.lock +8 -2
- data/README.md +43 -6
- data/bin/console +2 -5
- data/lib/sms_pilot.rb +5 -1
- data/lib/sms_pilot/client.rb +209 -90
- data/lib/sms_pilot/errors.rb +1 -0
- data/lib/sms_pilot/version.rb +1 -1
- data/sms-pilot-api-v1.gemspec +7 -4
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2cdf5eab949b7c36ae220eec407cd1afce5e9fb5df2b7c09c8b7e05327bc67f5
|
4
|
+
data.tar.gz: a001b60a5975b0ed50aa69b4f2b66e3d974e001cacf6af949a60617a234d6fe6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
39
|
+
## [0.0.3] - 6 May 2021
|
10
40
|
|
11
41
|
- Initial release
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,12 +1,17 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
sms-pilot-api-v1 (0.0.
|
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.
|
40
|
+
2.2.17
|
data/README.md
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# SmsPilot API v1 client
|
2
2
|
|
3
3
|
[](https://badge.fury.io/rb/sms-pilot-api-v1)
|
4
|
+
[](https://codeclimate.com/github/sergeypedan/sms-pilot-api-v1/maintainability)
|
5
|
+
[](https://codeclimate.com/github/sergeypedan/sms-pilot-api-v1/test_coverage)
|
6
|
+
[](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
|
-
##
|
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
|
-
|
36
|
-
|
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", "Привет, мир!")
|
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
|
-
- [
|
149
|
+
- [Web version](https://smspilot.ru/apikey.php) — см. вкладку PHP, в остальных ничего нет
|
128
150
|
- [PDF version](https://smspilot.ru/download/SMSPilotRu-HTTP-v1.9.19.pdf) — тут намного подробнее
|
129
|
-
- [
|
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
|
-
|
12
|
-
|
13
|
-
|
14
|
-
require "irb"
|
15
|
-
IRB.start(__FILE__)
|
11
|
+
require "pry"
|
12
|
+
Pry.start
|
data/lib/sms_pilot.rb
CHANGED
data/lib/sms_pilot/client.rb
CHANGED
@@ -7,7 +7,9 @@ require "uri"
|
|
7
7
|
module SmsPilot
|
8
8
|
|
9
9
|
# @!attribute [r] api_key
|
10
|
-
# @return [String]
|
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
|
-
|
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
|
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
|
-
@
|
148
|
-
@
|
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
|
-
|
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
|
-
|
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
|
-
@
|
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
|
-
|
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
|
-
|
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
|
-
|
326
|
+
response_data["send"] != nil
|
275
327
|
end
|
276
328
|
|
277
329
|
|
278
|
-
#
|
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
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
#
|
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.
|
340
|
+
# client.url #=> "https://smspilot.ru/api.php?api_key=XXX&format=json&send=TEXT&to=79021234567"
|
294
341
|
#
|
295
|
-
|
296
|
-
|
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({
|
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
|
-
#
|
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 [
|
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::
|
339
|
-
# @raise [SmsPilot::
|
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
|
343
|
-
fail SmsPilot::
|
344
|
-
fail SmsPilot::
|
345
|
-
|
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
|
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
|
-
#
|
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
|
data/lib/sms_pilot/errors.rb
CHANGED
data/lib/sms_pilot/version.rb
CHANGED
data/sms-pilot-api-v1.gemspec
CHANGED
@@ -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
|
-
|
18
|
+
"changelog_uri" => "#{spec.homepage}/blob/master/CHANGELOG.md",
|
19
19
|
"documentation_uri" => "https://rubydoc.info/github/sergeypedan/#{spec.name}/master/",
|
20
|
-
|
21
|
-
|
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 = "
|
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
|
+
version: 0.0.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sergey Pedan
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-05-
|
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
|