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