sms-pilot-api-v1 0.0.5 → 0.0.10

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: 2f18c87d0d06449a2d1990eefe98e92a66e2e543e6d37cadb8a59597fb165232
4
- data.tar.gz: 27b96c2afab4411c63474d807692336d32e95196d1172114f5ffaf9ddbb6d650
3
+ metadata.gz: e18ed848bce6fc14c2011704a417ebcd18b26a2364d6eded6f70c4bf8e0fd37a
4
+ data.tar.gz: 8c0fc16b26a26194ebd2543aa231f0b41b74181141de85f4530114c2045c55ac
5
5
  SHA512:
6
- metadata.gz: 5f59608daac142c675c71485c2ab63fa0a1291ebecc887f939a3a272d586a806f8cea5068174064ba9ff193172f0975836512136ac3a75f7b843f3afb1ab113e
7
- data.tar.gz: 9aeae9908fd518c5156b472f27c618f57c48d1370e09a2ffa8ab40430c083a908bc684fc15e3a1e76397f1d47b66c4c43c7c87da0fa89651a7006e5210317ddd
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.4] - 9 May 2021
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
- - Corrects what `#send_sms` returns (could return String errors instead of Booleans)
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] - 6 May 2021
76
+ ## [0.0.3] - 2021-05-06
10
77
 
11
78
  - Initial release
data/Gemfile CHANGED
@@ -5,5 +5,10 @@ source "https://rubygems.org"
5
5
  # Specify your gem's dependencies in gemspec
6
6
  gemspec
7
7
 
8
- gem "rake", "~> 13.0"
9
- gem "rspec", "~> 3.0"
8
+ gem "pry"
9
+ gem "rake"
10
+
11
+ group :test do
12
+ gem "rspec"
13
+ gem "webmock"
14
+ end
data/Gemfile.lock CHANGED
@@ -1,13 +1,25 @@
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
+ 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
- rake (~> 13.0)
30
- rspec (~> 3.0)
45
+ pry
46
+ rake
47
+ rspec
31
48
  sms-pilot-api-v1!
49
+ webmock
32
50
 
33
51
  BUNDLED WITH
34
- 2.2.11
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&amp;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,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
- client = SmsPilot::Client.new(api_key: "XXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZXXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZ")
36
- client = SmsPilot::Client.new(api_key: "XXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZXXXXXXXXXXXXYYYYYYYYYYYYZZZZZZZZ", locale: :en) # Available locales are [:en, :ru]
37
- #<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]
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", "Привет, мир!") # => true
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
- - [web version](https://smspilot.ru/apikey.php) — см. вкладку PHP, в остальных ничего нет
150
+ - [Web version](https://smspilot.ru/apikey.php) — см. вкладку PHP, в остальных ничего нет
129
151
  - [PDF version](https://smspilot.ru/download/SMSPilotRu-HTTP-v1.9.19.pdf) — тут намного подробнее
130
- - [Коды ошибок](https://smspilot.ru/apikey.php#err)
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
- # 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,5 +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"
@@ -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
@@ -18,13 +20,19 @@ module SmsPilot
18
20
  # @see #error_description
19
21
  #
20
22
  # @!attribute [r] locale
21
- # @return [Symbol] Chosen locale (affects only the language of errors)
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 = build_uri(@phone, message)
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
- @response_data = JSON.parse @response_body
144
+ response = persist_response_details Net::HTTP.get_response(@uri)
163
145
 
164
- if rejected?
165
- @error = "#{error_description} (error code: #{error_code})"
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
- return true
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
- @response_data["balance"]&.to_f if sms_sent?
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
- @response_data["error"].is_a? Hash
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
- @response_data["cost"] if sms_sent?
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
- @response_data["send"] != nil
328
+ response_data["send"] != nil
282
329
  end
283
330
 
284
331
 
285
- # SMS delivery status, as returned by the API
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
- # Code | Name | Final? | Description
291
- # ----:|:--------------|:-------|:-------------
292
- # -2 | Ошибка | Да | Ошибка, неправильные параметры запроса
293
- # -1 | Не доставлено | Да | Сообщение не доставлено (не в сети, заблокирован, не взял трубку), PING — не в сети, HLR — не обслуживается (заблокирован)
294
- # 0 | Новое | Нет | Новое сообщение/запрос, ожидает обработки у нас на сервере
295
- # 1 | В очереди | Нет | Сообщение или запрос ожидают отправки на сервере оператора
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.sms_status #=> 2
342
+ # client.url #=> "https://smspilot.ru/api.php?api_key=XXX&format=json&send=TEXT&to=79021234567"
301
343
  #
302
- def sms_status
303
- @response_data.dig("send", 0, "status")&.to_i if sms_sent?
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
- private def build_uri(phone, text)
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({ apikey: @api_key, format: :json, send: text, to: phone })
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
- # @return [nil]
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
- # @return [nil]
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
@@ -2,9 +2,10 @@
2
2
 
3
3
  module SmsPilot
4
4
 
5
- class InvalidAPIkeyError < ArgumentError; end
6
- class InvalidMessageError < ArgumentError; end
7
- class InvalidPhoneError < ArgumentError; end
8
- class InvalidLocaleError < ArgumentError; end
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
@@ -3,6 +3,6 @@
3
3
  module SmsPilot
4
4
 
5
5
  # Gem version
6
- VERSION = "0.0.5"
6
+ VERSION = "0.0.10"
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.5
4
+ version: 0.0.10
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-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