sms-pilot-api-v1 0.0.5 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +70 -3
- data/Gemfile +7 -2
- data/Gemfile.lock +22 -4
- data/README.md +44 -7
- data/bin/console +2 -5
- data/lib/sms_pilot.rb +5 -0
- data/lib/sms_pilot/client.rb +183 -82
- data/lib/sms_pilot/errors.rb +5 -4
- 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: e18ed848bce6fc14c2011704a417ebcd18b26a2364d6eded6f70c4bf8e0fd37a
|
4
|
+
data.tar.gz: 8c0fc16b26a26194ebd2543aa231f0b41b74181141de85f4530114c2045c55ac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 64fad357cc93e5b0901db4c15a6965881e205fbb45ef3637d196d280ef11e089595e8e402ad81030883f51472c33716f239381343a05b58d01a334879b46678a
|
7
|
+
data.tar.gz: 172f139edc7163d805edd08a891cbeb1e1789832693b706fe99f5fc76b41f4b40fdc6aada62977b1c84df7d69a0539dad76df465aee66371ca3d144a39ca7444
|
data/CHANGELOG.md
CHANGED
@@ -1,11 +1,78 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
## [0.0.
|
3
|
+
## [0.0.10] - 2021-05-11
|
4
|
+
|
5
|
+
### Added
|
6
|
+
|
7
|
+
- Accepts sender name in [`#initialize`](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot%2FClient:initialize)
|
8
|
+
- Tests for `send_sms`
|
9
|
+
|
10
|
+
## [0.0.9] - 2021-05-10
|
11
|
+
|
12
|
+
### Added
|
13
|
+
|
14
|
+
- Passes `charset` attribute to the API in [`#build_uri`](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot%2FClient:build_uri)
|
15
|
+
- Passes `lang` attribute to the API in [`#build_uri`](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot%2FClient:build_uri)
|
16
|
+
|
17
|
+
### Changed
|
18
|
+
|
19
|
+
- Stores constant request params in constants
|
20
|
+
|
21
|
+
### Deprecated
|
22
|
+
|
23
|
+
- 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)
|
24
|
+
|
25
|
+
## [0.0.8] - 2021-05-10
|
26
|
+
|
27
|
+
### Added
|
28
|
+
|
29
|
+
- [`#broadcast_id`](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot%2FClient:broadcast_id) method
|
30
|
+
- [roadmap section](https://github.com/sergeypedan/sms-pilot-api-v1#roadmap) in the Readme
|
31
|
+
|
32
|
+
## [0.0.7] - 2021-05-09
|
33
|
+
|
34
|
+
### Changed
|
35
|
+
|
36
|
+
- Returns original values from validation methods
|
37
|
+
- Offloads parsing response body to a method
|
38
|
+
- Improves documentation
|
39
|
+
|
40
|
+
### Added
|
41
|
+
|
42
|
+
- Adds CodeClimate badges
|
43
|
+
- Writes tests for [`#initialize`](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot%2FClient:initialize)
|
44
|
+
- Writes tests for [`#api_key`](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot%2FClient:api_key)
|
45
|
+
|
46
|
+
## [0.0.6] - 2021-05-09
|
47
|
+
|
48
|
+
### Fixed
|
49
|
+
|
50
|
+
- Corrects cost type
|
51
|
+
|
52
|
+
### Changed
|
53
|
+
|
54
|
+
- Switches to PRY in console
|
55
|
+
|
56
|
+
## [0.0.5] - 2021-05-09
|
57
|
+
|
58
|
+
### Added
|
59
|
+
|
60
|
+
- Adds locale support (RU / EN)
|
61
|
+
|
62
|
+
## [0.0.4] - 2021-05-09
|
63
|
+
|
64
|
+
### Fixed
|
65
|
+
|
66
|
+
- 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)
|
67
|
+
|
68
|
+
### Changed
|
4
69
|
|
5
70
|
- Drop dependence on HTTP.rb gem
|
6
|
-
|
71
|
+
|
72
|
+
### Added
|
73
|
+
|
7
74
|
- Adds extensive [documentation](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot/Client) via YARD & RubyDoc
|
8
75
|
|
9
|
-
## [0.0.3] -
|
76
|
+
## [0.0.3] - 2021-05-06
|
10
77
|
|
11
78
|
- Initial release
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,13 +1,25 @@
|
|
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
|
+
addressable (2.7.0)
|
10
|
+
public_suffix (>= 2.0.2, < 5.0)
|
11
|
+
coderay (1.1.3)
|
12
|
+
crack (0.4.5)
|
13
|
+
rexml
|
9
14
|
diff-lcs (1.4.4)
|
15
|
+
hashdiff (1.0.1)
|
16
|
+
method_source (1.0.0)
|
17
|
+
pry (0.14.1)
|
18
|
+
coderay (~> 1.1)
|
19
|
+
method_source (~> 1.0)
|
20
|
+
public_suffix (4.0.6)
|
10
21
|
rake (13.0.3)
|
22
|
+
rexml (3.2.5)
|
11
23
|
rspec (3.10.0)
|
12
24
|
rspec-core (~> 3.10.0)
|
13
25
|
rspec-expectations (~> 3.10.0)
|
@@ -21,14 +33,20 @@ GEM
|
|
21
33
|
diff-lcs (>= 1.2.0, < 2.0)
|
22
34
|
rspec-support (~> 3.10.0)
|
23
35
|
rspec-support (3.10.2)
|
36
|
+
webmock (3.12.2)
|
37
|
+
addressable (>= 2.3.6)
|
38
|
+
crack (>= 0.3.2)
|
39
|
+
hashdiff (>= 0.4.0, < 2.0.0)
|
24
40
|
|
25
41
|
PLATFORMS
|
26
42
|
x86_64-darwin-17
|
27
43
|
|
28
44
|
DEPENDENCIES
|
29
|
-
|
30
|
-
|
45
|
+
pry
|
46
|
+
rake
|
47
|
+
rspec
|
31
48
|
sms-pilot-api-v1!
|
49
|
+
webmock
|
32
50
|
|
33
51
|
BUNDLED WITH
|
34
|
-
2.2.
|
52
|
+
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,21 +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
|
-
|
37
|
-
|
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]
|
38
45
|
```
|
39
46
|
|
47
|
+
Method [documentation](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot/Client#initialize-instance_method) at RubyDoc.
|
48
|
+
|
40
49
|
### Before sending
|
41
50
|
|
51
|
+
There are a bunch of methods describing the state of affairs:
|
52
|
+
|
42
53
|
```ruby
|
43
54
|
client.api_key # => "YOUR API KEY"
|
44
55
|
client.balance # => nil
|
56
|
+
client.broadcast_id # => nil
|
45
57
|
client.error # => nil
|
46
58
|
client.phone # => nil
|
47
59
|
client.rejected? # => false
|
@@ -56,20 +68,28 @@ client.sms_status # => nil
|
|
56
68
|
client.url # => nil
|
57
69
|
```
|
58
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
|
+
|
59
75
|
### Sending SMS
|
60
76
|
|
61
77
|
```ruby
|
62
|
-
client.send_sms("+7 (902) 123-45-67", "Привет, мир!")
|
78
|
+
client.send_sms("+7 (902) 123-45-67", "Привет, мир!")
|
79
|
+
client.send_sms("+7 (902) 123-45-67", "Привет, мир!", "ФССПРФ")
|
80
|
+
# => true
|
63
81
|
```
|
64
82
|
|
65
83
|
Returns result of `sms_sent?`, so it’s either `true` or `false`.
|
66
84
|
|
85
|
+
Method [documentation](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot/Client#send_sms-instance_method) at RubyDoc.
|
67
86
|
|
68
87
|
### Sending SMS succeeded
|
69
88
|
|
70
89
|
```ruby
|
71
90
|
client.api_key # => "YOUR API KEY"
|
72
91
|
client.balance # => 20006.97
|
92
|
+
client.broadcast_id # => 10000
|
73
93
|
client.error # => nil
|
74
94
|
client.phone # => "79021234567"
|
75
95
|
client.rejected? # => false
|
@@ -89,6 +109,7 @@ client.url # => "https://smspilot.ru/api.php?apikey=1234567890&form
|
|
89
109
|
```ruby
|
90
110
|
client.api_key # => "YOUR API KEY"
|
91
111
|
client.balance # => nil
|
112
|
+
client.broadcast_id # => nil
|
92
113
|
client.error # => "Неправильный API-ключ (см. настройки API в личном кабинете) (код ошибки: 101)"
|
93
114
|
client.phone # => "79021234567"
|
94
115
|
client.rejected? # => true
|
@@ -108,6 +129,7 @@ client.url # => "https://smspilot.ru/api.php?apikey=1234567890&form
|
|
108
129
|
```ruby
|
109
130
|
client.api_key # => "YOUR API KEY"
|
110
131
|
client.balance # => nil
|
132
|
+
client.broadcast_id # => nil
|
111
133
|
client.error # => "HTTP request failed with code 404"
|
112
134
|
client.phone # => "79021234567"
|
113
135
|
client.rejected? # => false
|
@@ -125,9 +147,9 @@ client.url # => "https://smspilot.ru/api.php?apikey=1234567890&form
|
|
125
147
|
|
126
148
|
## SMS pilot API docs
|
127
149
|
|
128
|
-
- [
|
150
|
+
- [Web version](https://smspilot.ru/apikey.php) — см. вкладку PHP, в остальных ничего нет
|
129
151
|
- [PDF version](https://smspilot.ru/download/SMSPilotRu-HTTP-v1.9.19.pdf) — тут намного подробнее
|
130
|
-
- [
|
152
|
+
- [API error code](https://smspilot.ru/apikey.php#err)
|
131
153
|
|
132
154
|
|
133
155
|
## Test API key
|
@@ -164,3 +186,18 @@ SMS rejected:
|
|
164
186
|
}
|
165
187
|
}
|
166
188
|
```
|
189
|
+
|
190
|
+
|
191
|
+
## Documentation
|
192
|
+
|
193
|
+
See [structured documentation](https://rubydoc.info/github/sergeypedan/sms-pilot-api-v1/master/SmsPilot/Client) at RubyDoc.
|
194
|
+
|
195
|
+
|
196
|
+
## Roadmap
|
197
|
+
|
198
|
+
1. Switch to POST to escape 1024 symbolos GET request limit
|
199
|
+
1. Support passing `sender` to the API
|
200
|
+
1. Switch to result object pattern
|
201
|
+
1. Проверка статусов SMS
|
202
|
+
1. Проверка баланса
|
203
|
+
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
|
@@ -18,13 +20,19 @@ module SmsPilot
|
|
18
20
|
# @see #error_description
|
19
21
|
#
|
20
22
|
# @!attribute [r] locale
|
21
|
-
#
|
23
|
+
# Chosen locale (affects only the language of errors)
|
24
|
+
#
|
25
|
+
# @return [Symbol]
|
26
|
+
# @example
|
27
|
+
# client.locale #=> :ru
|
22
28
|
#
|
23
29
|
# @!attribute [r] phone
|
24
30
|
# @return [nil, String] phone after normalization
|
31
|
+
# @example
|
32
|
+
# client.phone #=> "79021234567"
|
25
33
|
#
|
26
34
|
# @!attribute [r] response_body
|
27
|
-
# 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}).
|
28
36
|
# @example
|
29
37
|
# "{\"send\":[{\"server_id\":\"10000\",\"phone\":\"79021234567\",\"price\":\"1.68\",\"status\":\"0\"}],\"balance\":\"20006.97\",\"cost\":\"1.68\"}"
|
30
38
|
# @return [nil, String] Unmodified HTTP resonse body that API returned
|
@@ -32,28 +40,9 @@ module SmsPilot
|
|
32
40
|
# @see #response_headers
|
33
41
|
# @see #response_status
|
34
42
|
#
|
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
43
|
# @!attribute [r] response_headers
|
56
44
|
# @example
|
45
|
+
# client.response_headers #=>
|
57
46
|
# {
|
58
47
|
# "Access-Control-Allow-Origin" => "*",
|
59
48
|
# "Connection" => "close",
|
@@ -77,38 +66,42 @@ module SmsPilot
|
|
77
66
|
# @see #response_data
|
78
67
|
# @see #response_headers
|
79
68
|
#
|
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
|
-
#
|
85
69
|
class Client
|
86
70
|
|
87
71
|
# Check current API endpoint URL at {https://smspilot.ru/apikey.php#api1}
|
88
72
|
#
|
89
73
|
API_ENDPOINT = "https://smspilot.ru/api.php".freeze
|
74
|
+
|
75
|
+
# Locale influences only the language of API errors
|
76
|
+
#
|
90
77
|
AVAILABLE_LOCALES = [:ru, :en].freeze
|
91
78
|
|
79
|
+
REQUEST_ACCEPT_FORMAT = "json".freeze
|
80
|
+
REQUEST_CHARSET = "utf-8".freeze
|
81
|
+
|
92
82
|
attr_reader :api_key
|
93
83
|
attr_reader :error
|
94
84
|
attr_reader :locale
|
95
85
|
attr_reader :phone
|
96
86
|
attr_reader :response_body
|
97
|
-
attr_reader :response_data
|
98
87
|
attr_reader :response_headers
|
99
88
|
attr_reader :response_status
|
100
|
-
attr_reader :url
|
101
89
|
|
102
90
|
|
103
91
|
# @param api_key [String]
|
92
|
+
# @param locale [Symbol]
|
93
|
+
#
|
104
94
|
# @return [SmsPilot::Client]
|
105
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
|
+
#
|
106
98
|
# @see https://smspilot.ru/my-settings.php Get your production API key here
|
107
99
|
# @see https://smspilot.ru/apikey.php Get your development API key here
|
108
100
|
# @note Current development API key is <tt>"XXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZXXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZ"</tt>
|
109
101
|
#
|
110
102
|
# @example
|
111
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)
|
112
105
|
#
|
113
106
|
def initialize(api_key:, locale: AVAILABLE_LOCALES[0])
|
114
107
|
@api_key = validate_api_key!(api_key)
|
@@ -117,8 +110,6 @@ module SmsPilot
|
|
117
110
|
@response_status = nil
|
118
111
|
@response_headers = {}
|
119
112
|
@response_body = nil
|
120
|
-
@response_data = {}
|
121
|
-
@url = nil
|
122
113
|
end
|
123
114
|
|
124
115
|
|
@@ -136,37 +127,26 @@ module SmsPilot
|
|
136
127
|
# @raise [SmsPilot::InvalidMessageError] if your message is empty
|
137
128
|
# @raise [SmsPilot::InvalidPhoneError] if your phone is empty
|
138
129
|
# @raise [SmsPilot::InvalidPhoneError] if your phone has no digits
|
130
|
+
# @raise [URI::InvalidURIError] but is almost impossible, because we provide the URL ourselves
|
139
131
|
#
|
140
132
|
# @example
|
141
133
|
# client.send_sms("+7 (902) 123-45-67", "Привет, мир!") # => true
|
134
|
+
# client.send_sms("+7 (902) 123-45-67", "Привет, мир!", "ФССПРФ") # => true
|
142
135
|
#
|
143
|
-
def send_sms(phone, message)
|
136
|
+
def send_sms(phone, message, sender_name = nil)
|
144
137
|
validate_phone! phone
|
145
138
|
validate_message! message
|
139
|
+
validate_sender_name! sender_name
|
146
140
|
|
147
141
|
@phone = normalize_phone(phone)
|
148
|
-
uri
|
149
|
-
@url = uri.to_s
|
150
|
-
|
151
|
-
response = Net::HTTP.get_response(uri)
|
152
|
-
|
153
|
-
@response_body = response.body
|
154
|
-
@response_status = response.code.to_i
|
155
|
-
@response_headers = response.each_capitalized.to_h
|
156
|
-
|
157
|
-
unless response.is_a?(Net::HTTPSuccess)
|
158
|
-
@error = "HTTP request failed with code #{response.code}"
|
159
|
-
return false
|
160
|
-
end
|
142
|
+
@uri = build_uri(@phone, message, sender_name)
|
161
143
|
|
162
|
-
|
144
|
+
response = persist_response_details Net::HTTP.get_response(@uri)
|
163
145
|
|
164
|
-
|
165
|
-
|
166
|
-
return false
|
167
|
-
end
|
146
|
+
@error = "HTTP request failed with code #{response.code}" and return false unless response.is_a?(Net::HTTPSuccess)
|
147
|
+
@error = "#{error_description} (error code: #{error_code})" and return false if rejected?
|
168
148
|
|
169
|
-
|
149
|
+
true
|
170
150
|
|
171
151
|
rescue JSON::ParserError => error
|
172
152
|
@error = "API returned invalid JSON. #{error.message}"
|
@@ -191,7 +171,45 @@ module SmsPilot
|
|
191
171
|
# client.balance #=> 20215.25
|
192
172
|
#
|
193
173
|
def balance
|
194
|
-
|
174
|
+
response_data["balance"]&.to_f if sms_sent?
|
175
|
+
end
|
176
|
+
|
177
|
+
|
178
|
+
# 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)
|
179
|
+
#
|
180
|
+
# @example
|
181
|
+
# client.broadcast_id #=> 10000
|
182
|
+
#
|
183
|
+
# @return [nil, Integer]
|
184
|
+
#
|
185
|
+
# @see #response_data
|
186
|
+
#
|
187
|
+
def broadcast_id
|
188
|
+
@response_data.dig("send", 0, "server_id")&.to_i if sms_sent?
|
189
|
+
end
|
190
|
+
|
191
|
+
|
192
|
+
# SMS delivery status, as returned by the API
|
193
|
+
#
|
194
|
+
# @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.
|
195
|
+
# @see https://smspilot.ru/apikey.php#status List of available statuses at API documentation website
|
196
|
+
#
|
197
|
+
# Code | Name | Final? | Description
|
198
|
+
# ----:|:--------------|:-------|:-------------
|
199
|
+
# -2 | Ошибка | Да | Ошибка, неправильные параметры запроса
|
200
|
+
# -1 | Не доставлено | Да | Сообщение не доставлено (не в сети, заблокирован, не взял трубку), PING — не в сети, HLR — не обслуживается (заблокирован)
|
201
|
+
# 0 | Новое | Нет | Новое сообщение/запрос, ожидает обработки у нас на сервере
|
202
|
+
# 1 | В очереди | Нет | Сообщение или запрос ожидают отправки на сервере оператора
|
203
|
+
# 2 | Доставлено | Да | Доставлено, звонок совершен, PING — в сети, HLR — обслуживается
|
204
|
+
# 3 | Отложено | Нет | Отложенная отправка, отправка сообщения/запроса запланирована на другое время
|
205
|
+
#
|
206
|
+
# @example
|
207
|
+
# client.broadcast_status #=> 2
|
208
|
+
#
|
209
|
+
# @see #sms_status
|
210
|
+
#
|
211
|
+
def broadcast_status
|
212
|
+
@response_data.dig("send", 0, "status")&.to_i if sms_sent?
|
195
213
|
end
|
196
214
|
|
197
215
|
|
@@ -232,7 +250,36 @@ module SmsPilot
|
|
232
250
|
#
|
233
251
|
def rejected?
|
234
252
|
return false if sms_sent?
|
235
|
-
|
253
|
+
response_data["error"].is_a? Hash
|
254
|
+
end
|
255
|
+
|
256
|
+
|
257
|
+
# Parses <tt>@response_body</tt> and memoizes result in <tt>@response_data</tt>
|
258
|
+
#
|
259
|
+
# @example
|
260
|
+
# {
|
261
|
+
# "balance" => "20006.97",
|
262
|
+
# "cost" => "1.68",
|
263
|
+
# "send" => [
|
264
|
+
# {
|
265
|
+
# "phone" => "79021234567",
|
266
|
+
# "price" => "1.68",
|
267
|
+
# "server_id" => "10000",
|
268
|
+
# "status" => "0"
|
269
|
+
# }
|
270
|
+
# ]
|
271
|
+
# }
|
272
|
+
#
|
273
|
+
# @return [Hash]
|
274
|
+
# @raise [JSON::ParserError] which is rescued in {#send_sms}
|
275
|
+
#
|
276
|
+
# @see #response_body
|
277
|
+
# @see #response_headers
|
278
|
+
# @see #response_status
|
279
|
+
#
|
280
|
+
def response_data
|
281
|
+
return {} unless @response_body
|
282
|
+
@response_data ||= JSON.parse @response_body
|
236
283
|
end
|
237
284
|
|
238
285
|
|
@@ -263,7 +310,7 @@ module SmsPilot
|
|
263
310
|
# client.sms_cost #=> 2.63
|
264
311
|
#
|
265
312
|
def sms_cost
|
266
|
-
|
313
|
+
response_data["cost"]&.to_f if sms_sent?
|
267
314
|
end
|
268
315
|
|
269
316
|
|
@@ -278,54 +325,74 @@ module SmsPilot
|
|
278
325
|
# client.sms_sent? #=> true
|
279
326
|
#
|
280
327
|
def sms_sent?
|
281
|
-
|
328
|
+
response_data["send"] != nil
|
282
329
|
end
|
283
330
|
|
284
331
|
|
285
|
-
#
|
286
|
-
#
|
287
|
-
# @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.
|
288
|
-
# @see https://smspilot.ru/apikey.php#status List of available statuses at API documentation website
|
332
|
+
# @deprecated (in favor of {#broadcast_status})
|
289
333
|
#
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
#
|
296
|
-
# 2 | Доставлено | Да | Доставлено, звонок совершен, PING — в сети, HLR — обслуживается
|
297
|
-
# 3 | Отложено | Нет | Отложенная отправка, отправка сообщения/запроса запланирована на другое время
|
334
|
+
def sms_status
|
335
|
+
broadcast_status
|
336
|
+
end
|
337
|
+
|
338
|
+
|
339
|
+
# URL generated by combining <tt>API_ENDPOINT</tt>, your API key, SMS text & phone
|
298
340
|
#
|
299
341
|
# @example
|
300
|
-
# client.
|
342
|
+
# client.url #=> "https://smspilot.ru/api.php?api_key=XXX&format=json&send=TEXT&to=79021234567"
|
301
343
|
#
|
302
|
-
|
303
|
-
|
344
|
+
# @return [nil, String]
|
345
|
+
#
|
346
|
+
def url
|
347
|
+
@uri&.to_s
|
304
348
|
end
|
305
349
|
|
306
350
|
# @!endgroup
|
307
351
|
|
308
352
|
|
309
353
|
# The URI we will send an HTTP request to
|
310
|
-
#
|
311
354
|
# @private
|
312
|
-
# @return [URI]
|
313
|
-
# @raise [URI::InvalidURIError] but is very unlikely because we provide the URL ourselves
|
314
355
|
#
|
315
356
|
# @example
|
316
357
|
# build_uri("79021234567", "Hello, World!")
|
317
358
|
# #=> #<URI::HTTPS https://smspilot.ru/api.php?apikey=XXX…&format=json&send=Hello%2C+World%21&to=79021234567>
|
318
359
|
#
|
319
|
-
|
360
|
+
# @return [URI]
|
361
|
+
# @raise [URI::InvalidURIError] but is almost impossible, because we provide the URL ourselves
|
362
|
+
#
|
363
|
+
# @param [String] phone
|
364
|
+
# @param [String] text
|
365
|
+
# @param [nil, String] sender_name
|
366
|
+
#
|
367
|
+
# @see #api_key
|
368
|
+
# @see #phone
|
369
|
+
# @see #validate_phone!
|
370
|
+
# @see #validate_message!
|
371
|
+
# @see #validate_sender_name!
|
372
|
+
#
|
373
|
+
private def build_uri(phone, text, sender_name)
|
374
|
+
attributes = {
|
375
|
+
apikey: @api_key,
|
376
|
+
charset: REQUEST_CHARSET,
|
377
|
+
format: REQUEST_ACCEPT_FORMAT,
|
378
|
+
lang: @locale,
|
379
|
+
send: text,
|
380
|
+
to: phone
|
381
|
+
}
|
382
|
+
attributes = attributes.merge({ sender: sender_name }) if sender_name
|
383
|
+
|
320
384
|
URI.parse(API_ENDPOINT).tap do |uri|
|
321
|
-
uri.query = URI.encode_www_form(
|
385
|
+
uri.query = URI.encode_www_form(attributes)
|
322
386
|
end
|
323
387
|
end
|
324
388
|
|
325
389
|
|
390
|
+
|
391
|
+
|
326
392
|
# Cleans up your phone from anything but digits. Also replaces 8 to 7 if it is the first digit.
|
327
393
|
#
|
328
394
|
# @private
|
395
|
+
# @param [String] phone
|
329
396
|
# @return [String]
|
330
397
|
#
|
331
398
|
# @example
|
@@ -337,6 +404,21 @@ module SmsPilot
|
|
337
404
|
end
|
338
405
|
|
339
406
|
|
407
|
+
# Saves response details into instance variables
|
408
|
+
# @private
|
409
|
+
#
|
410
|
+
# @return [response]
|
411
|
+
# @raise [TypeError] unless a Net::HTTPResponse passed
|
412
|
+
#
|
413
|
+
private def persist_response_details(response)
|
414
|
+
fail TypeError, "Net::HTTPResponse expected, you pass a #{response.class}" unless response.is_a? Net::HTTPResponse
|
415
|
+
@response_body = response.body
|
416
|
+
@response_status = response.code.to_i
|
417
|
+
@response_headers = response.each_capitalized.to_h
|
418
|
+
response
|
419
|
+
end
|
420
|
+
|
421
|
+
|
340
422
|
# @!group Validations
|
341
423
|
|
342
424
|
# Validates api_key
|
@@ -344,7 +426,7 @@ module SmsPilot
|
|
344
426
|
# @private
|
345
427
|
# @return [String] the original value passed into the method, only if it was valid
|
346
428
|
# @param [String] api_key
|
347
|
-
|
429
|
+
#
|
348
430
|
# @raise [SmsPilot::InvalidError] if api_key is not a String
|
349
431
|
# @raise [SmsPilot::InvalidError] if api_key is an empty String
|
350
432
|
#
|
@@ -360,7 +442,7 @@ module SmsPilot
|
|
360
442
|
# @private
|
361
443
|
# @return [Symbol] the original value passed into the method, only if it was valid
|
362
444
|
# @param [Symbol] locale
|
363
|
-
|
445
|
+
#
|
364
446
|
# @raise [SmsPilot::InvalidError] if locale is not a Symbol
|
365
447
|
# @raise [SmsPilot::InvalidError] if locale is unrecognized
|
366
448
|
#
|
@@ -372,9 +454,10 @@ module SmsPilot
|
|
372
454
|
|
373
455
|
|
374
456
|
# Validates message
|
375
|
-
#
|
376
457
|
# @private
|
377
|
-
#
|
458
|
+
#
|
459
|
+
# @param [String] message
|
460
|
+
# @return [String] the original value passed into the method, only if it was valid
|
378
461
|
#
|
379
462
|
# @raise [SmsPilot::InvalidMessageError] if you pass anythig but a String with the <tt>message</tt> argument
|
380
463
|
# @raise [SmsPilot::InvalidMessageError] if your message is empty
|
@@ -382,13 +465,15 @@ module SmsPilot
|
|
382
465
|
private def validate_message!(message)
|
383
466
|
fail SmsPilot::InvalidMessageError, "SMS message must be a String, you pass a #{ message.class} (#{ message})" unless message.is_a? String
|
384
467
|
fail SmsPilot::InvalidMessageError, "SMS message cannot be empty" if message == ""
|
468
|
+
message
|
385
469
|
end
|
386
470
|
|
387
471
|
|
388
472
|
# Validates phone
|
389
|
-
#
|
390
473
|
# @private
|
391
|
-
#
|
474
|
+
#
|
475
|
+
# @param [String] phone
|
476
|
+
# @return [String] the original value passed into the method, only if it was valid
|
392
477
|
#
|
393
478
|
# @raise [SmsPilot::InvalidPhoneError] if you pass anythig but a String with the <tt>phone</tt> argument
|
394
479
|
# @raise [SmsPilot::InvalidPhoneError] if your phone is empty
|
@@ -398,6 +483,22 @@ module SmsPilot
|
|
398
483
|
fail SmsPilot::InvalidPhoneError, "phone must be a String, you pass a #{phone.class} (#{phone})" unless phone.is_a? String
|
399
484
|
fail SmsPilot::InvalidPhoneError, "phone cannot be empty" if phone == ""
|
400
485
|
fail SmsPilot::InvalidPhoneError, "phone must contain digits" if phone.scan(/\d/).none?
|
486
|
+
phone
|
487
|
+
end
|
488
|
+
|
489
|
+
|
490
|
+
# Validates sender name
|
491
|
+
# @private
|
492
|
+
#
|
493
|
+
# @param [nil, String] sender_name
|
494
|
+
# @return [String] the original value passed into the method, only if it was valid
|
495
|
+
#
|
496
|
+
# @raise [SmsPilot::InvalidSenderNameError] if you pass anything but <tt>nil</tt> or non-empty <tt>String</tt>
|
497
|
+
#
|
498
|
+
private def validate_sender_name!(sender_name)
|
499
|
+
fail SmsPilot::InvalidSenderNameError, "sender name must be either nil or String" unless [NilClass, String].include? sender_name.class
|
500
|
+
fail SmsPilot::InvalidSenderNameError, "sender name cannot be empty" if sender_name == ""
|
501
|
+
sender_name
|
401
502
|
end
|
402
503
|
|
403
504
|
# @!endgroup
|
data/lib/sms_pilot/errors.rb
CHANGED
@@ -2,9 +2,10 @@
|
|
2
2
|
|
3
3
|
module SmsPilot
|
4
4
|
|
5
|
-
class InvalidAPIkeyError
|
6
|
-
class
|
7
|
-
class
|
8
|
-
class
|
5
|
+
class InvalidAPIkeyError < ArgumentError; end
|
6
|
+
class InvalidLocaleError < ArgumentError; end
|
7
|
+
class InvalidMessageError < ArgumentError; end
|
8
|
+
class InvalidPhoneError < ArgumentError; end
|
9
|
+
class InvalidSenderNameError < ArgumentError; end
|
9
10
|
|
10
11
|
end
|
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.10
|
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-11 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
|