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 +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
|
[![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
|
-
##
|
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
|