openmarket 0.0.1
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 +7 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +129 -0
- data/Rakefile +2 -0
- data/lib/open_market.rb +4 -0
- data/lib/open_market/api.rb +83 -0
- data/lib/open_market/configuration.rb +38 -0
- data/lib/open_market/dr.rb +27 -0
- data/lib/open_market/mo.rb +37 -0
- data/lib/open_market/response.rb +98 -0
- data/lib/open_market/version.rb +3 -0
- data/lib/openmarket.rb +1 -0
- data/open_market.gemspec +28 -0
- data/spec/api_spec.rb +220 -0
- data/spec/configuration_spec.rb +35 -0
- data/spec/support/configuration_from_yaml.rb +33 -0
- data/spec/support/secrets.yml.example +7 -0
- metadata +280 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 313f1285d8dfc0d1a615e4d0e34b8d833df72e35
|
4
|
+
data.tar.gz: 54bf9d7d27719f8883faf50abc03ccba6619e6a5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4b97d23e3d060dae73ae4489b75e2291ff8b8f491ab05be1d5dd76e6512a9584fc5234580e353b9a8848ea7fc1f262dc7215cbea5ad3757675def646e8662ede
|
7
|
+
data.tar.gz: f9e13cf97a53740a26f755e7d201cf92048c521cc78ccbaac75452462de1bb023e74e884d9787092ce42b4b875d66d0c3a8b2f9e2d6ece78c1947ef1a647484e
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Isaac Betesh
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
# OpenMarket
|
2
|
+
|
3
|
+
We use HTTParty to send SMS messages using the OpenMarket API. See USAGE below for details.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'openmarket'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install openmarket
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
### Configuratiion
|
24
|
+
|
25
|
+
The openmarket gem requires you to provide an id, password, program_id and short_code. Configure them before attempting any API calls.
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
OpenMarket.configure do |config|
|
29
|
+
config.id = "000-000-000-00000"
|
30
|
+
config.password = "Re@llyL0ngR&om$tr1ng"
|
31
|
+
config.program_id = "ABC"
|
32
|
+
config.short_code = 99999 # You can override this on an individual message if necessary
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
Since the openmarket gem depends on sms_validation (https://github.com/betesh/sms_validation/), it is also recommended that you configure sms_validation.
|
37
|
+
openmarket uses sms_validation's logger. In a Rails environment, you will probably want to rely on the default configuration,
|
38
|
+
but outside of Rails, you will need to configure it if you want any logging:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
SmsValidation.configure do |config|
|
42
|
+
config.logger = ::Logger.new(STDOUT)
|
43
|
+
end
|
44
|
+
```
|
45
|
+
|
46
|
+
### API calls
|
47
|
+
|
48
|
+
`OpenMarket::API` supports 3 API calls: `carrier_lookup`, `send_sms`, and `status`.
|
49
|
+
|
50
|
+
#### carrier_lookup
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
require 'openmarket'
|
54
|
+
phone = 2125551212
|
55
|
+
result = OpenMarket::API.carrier_lookup(phone)
|
56
|
+
|
57
|
+
# First, make sure the call succeeded
|
58
|
+
puts result.code # should be 0
|
59
|
+
puts result.description # should be 'No Error'
|
60
|
+
|
61
|
+
# If the call succeeded, you can check the carrier_id:
|
62
|
+
puts result.carrier_id # You are probably most interested in the carrier_id
|
63
|
+
puts result.inspect # But there are a lot of other attributes returned by this API call as well
|
64
|
+
```
|
65
|
+
|
66
|
+
#### send_sms
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
require 'openmarket'
|
70
|
+
phone = 2125551212
|
71
|
+
message = "Hello, this is a test of the OpenMarket API"
|
72
|
+
result = OpenMarket::API.send_sms(phone, message)
|
73
|
+
|
74
|
+
# First, make sure the call succeeded
|
75
|
+
puts result.code # should be 2
|
76
|
+
puts result.description # should be 'Message received.'
|
77
|
+
|
78
|
+
# Save the ticket ID for later. We'll use this to query the status of the ticket.
|
79
|
+
ticket_id = result.ticket_id
|
80
|
+
|
81
|
+
# Save the carrier ID for later. We'll use this next time we send an SMS to this number.
|
82
|
+
carrier_id = result.carrier_id
|
83
|
+
|
84
|
+
# There are some options you can pass along as well:
|
85
|
+
result = OpenMarket::API.send_sms(
|
86
|
+
phone,
|
87
|
+
message,
|
88
|
+
|
89
|
+
# If you want to receive DR's, you must pass a dr_url option. If you don't pass a URL, no DR will be sent to the default URL.
|
90
|
+
dr_url: "http://www.example.com/drs",
|
91
|
+
|
92
|
+
# It is highly recommended to pass a carrier_id. If you don't, the openmarket gem will make an extra API call to look up the carrier before sending the message.
|
93
|
+
carrier_id: carrier_id, # Remember the carrier ID we saved from the previous SMS?
|
94
|
+
|
95
|
+
# If you don't want to the short_code you configured above, provide another short_code to send to:
|
96
|
+
short_code: 33333,
|
97
|
+
|
98
|
+
# By default, OpenMarket re-attempts delivery for 3 days. To make OpenMarket give up and report it as a failure sooner, pass a number of minutes you would like to retry for:
|
99
|
+
minutes_to_retry: 120, # 2 hours
|
100
|
+
|
101
|
+
note: "Information that will be passed on to the DR",
|
102
|
+
|
103
|
+
ticket_id_for_retry: ticket_id # If this is a re-try of a failed ticket.
|
104
|
+
)
|
105
|
+
|
106
|
+
```
|
107
|
+
#### status
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
require 'openmarket'
|
111
|
+
result = OpenMarket::API.status(ticket_id) # Remember the ticket ID we saved from #send_sms?
|
112
|
+
|
113
|
+
# First, make sure the call succeeded
|
114
|
+
puts result.code # should be 0
|
115
|
+
puts result.description # should be 'No Error'
|
116
|
+
|
117
|
+
# Check the result of the SMS message
|
118
|
+
puts result.status_code
|
119
|
+
puts result.status_description
|
120
|
+
|
121
|
+
```
|
122
|
+
|
123
|
+
## Contributing
|
124
|
+
|
125
|
+
1. Fork it ( https://github.com/betesh/open_market/fork )
|
126
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
127
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
128
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
129
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/lib/open_market.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require "open_market/configuration"
|
2
|
+
require "open_market/response"
|
3
|
+
require "open_market/version"
|
4
|
+
|
5
|
+
require "builder"
|
6
|
+
require "httparty"
|
7
|
+
require "sms_validation"
|
8
|
+
|
9
|
+
module OpenMarket
|
10
|
+
class Api
|
11
|
+
class Http
|
12
|
+
include HTTParty
|
13
|
+
base_uri "https://smsc.openmarket.com"
|
14
|
+
end
|
15
|
+
|
16
|
+
ALLOWED_OPTIONS = [:dr_url, :ticket_id_for_retry, :carrier_id, :note, :minutes_to_retry, :short_code]
|
17
|
+
class InvalidOptions < ::StandardError; end
|
18
|
+
|
19
|
+
def carrier_lookup(phone)
|
20
|
+
CarrierLookupResponse.new(post(:preview) do |b|
|
21
|
+
b.destination(ton: 1, address: "1#{phone.to_s[-10..-1]}")
|
22
|
+
end)
|
23
|
+
end
|
24
|
+
|
25
|
+
def send_sms(phone, message, options = {})
|
26
|
+
phone = SmsValidation::Sms.new(phone, message).phone
|
27
|
+
options = options.inject({}) { |hash, (k,v)| hash[k.to_sym] = v; hash }
|
28
|
+
unrecognized_keys = options.keys - ALLOWED_OPTIONS
|
29
|
+
raise InvalidOptions, "#{unrecognized_keys.join(", ")} #{1 == unrecognized_keys.size ? "is not a" : "are not"} valid option#{:s if unrecognized_keys.size > 1}" unless unrecognized_keys.empty?
|
30
|
+
request_options = options.select{ |k,v| k.to_sym == :ticket_id_for_retry }
|
31
|
+
carrier_id = options[:carrier_id] || carrier_lookup(phone).carrier_id
|
32
|
+
SendSmsResponse.new(post(:submit, request_options) do |b|
|
33
|
+
b.delivery(receipt_requested: true, url: options[:dr_url]) if options[:dr_url]
|
34
|
+
b.option((options[:note] ? { note: options[:note] } : {}).merge(charge_type: 0, program_id: configuration.program_id, mlc: message_length_control))
|
35
|
+
b.source(ton: 3, address: options[:short_code] || configuration.short_code)
|
36
|
+
b.destination(ton: 1, address: phone, carrier: carrier_id)
|
37
|
+
b.message((options[:minutes_to_retry] ? { validity_period: (options[:minutes_to_retry].to_f * 60).round } : {}).merge(text: message))
|
38
|
+
end, carrier_id)
|
39
|
+
end
|
40
|
+
|
41
|
+
def status(ticket_id)
|
42
|
+
StatusResponse.new(post(:query) do |b|
|
43
|
+
b.ticket(id: ticket_id)
|
44
|
+
end)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def configuration
|
49
|
+
@configuration ||= Module.nesting.last.configuration
|
50
|
+
end
|
51
|
+
|
52
|
+
def filtered(value)
|
53
|
+
[:account, :user].inject(value) { |v, k| v.gsub(/<#{k}.*?\/>/, "") }
|
54
|
+
end
|
55
|
+
|
56
|
+
def post(type, options = {})
|
57
|
+
builder = Builder::XmlMarkup.new
|
58
|
+
builder.instruct!(:xml, version: 1.0)
|
59
|
+
body = builder.request(options.merge(version: 3.0, protocol: :wmp, type: type)) do |r|
|
60
|
+
r.user(agent: "openmarket_rubygem/SMS/#{OpenMarket::VERSION}")
|
61
|
+
r.account(id: configuration.id, password: configuration.password)
|
62
|
+
yield r
|
63
|
+
end
|
64
|
+
SmsValidation.log { "OpenMarket API: POST #{filtered(body)}" }
|
65
|
+
Http.post("/wmp", body: body.to_s).tap do |result|
|
66
|
+
SmsValidation.log { "OpenMarket API Result: #{result.respond_to?(:body) ? result.body : result}" }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def message_length_control
|
71
|
+
case SmsValidation.configuration.on_message_too_long
|
72
|
+
when :truncate
|
73
|
+
1
|
74
|
+
when :raise_error
|
75
|
+
0
|
76
|
+
when :split
|
77
|
+
2
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
API ||= Api.new
|
83
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module OpenMarket
|
2
|
+
class << self
|
3
|
+
def configuration
|
4
|
+
@configuration ||= Configuration.new
|
5
|
+
end
|
6
|
+
|
7
|
+
def configure
|
8
|
+
yield configuration
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Configuration
|
13
|
+
class Error < ::StandardError; end
|
14
|
+
CONFIGURATION_OPTIONS = [:id, :password, :program_id, :short_code]
|
15
|
+
|
16
|
+
(CONFIGURATION_OPTIONS - [:short_code]).each do |accessor|
|
17
|
+
define_method(:"#{accessor}=") do |arg|
|
18
|
+
raise Error, "#{accessor} must be a String" unless arg.nil? || arg.is_a?(String)
|
19
|
+
raise Error, "#{accessor} cannot be blank" if arg.nil? || arg.empty?
|
20
|
+
instance_variable_set("@#{accessor}", arg)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def short_code=(arg)
|
25
|
+
raise Error, "short_code cannot be blank" if arg.nil?
|
26
|
+
raise Error, "short_code must be a 5-digit number" unless arg.to_s.scan(/\A[0-9]{5}\z/)
|
27
|
+
@short_code = arg
|
28
|
+
end
|
29
|
+
|
30
|
+
CONFIGURATION_OPTIONS.each do |accessor|
|
31
|
+
define_method(accessor) do
|
32
|
+
instance_variable_get("@#{accessor}").tap do |result|
|
33
|
+
raise Error, "#{accessor} has not been set. Set it with `#{Module.nesting.last}.configuration.#{accessor} = ...`" if result.nil?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "rexml/document"
|
2
|
+
|
3
|
+
module OpenMarket
|
4
|
+
class DR
|
5
|
+
attr_reader :code, :description, :note, :parent_ticket_id, :segment_number, :state_description, :state_id, :ticket_id, :timestamp
|
6
|
+
def initialize(data)
|
7
|
+
(class << self; self; end).class_eval do
|
8
|
+
# Defining a member variable for xml would pollute #inspect
|
9
|
+
# This solution is inspired by https://github.com/jordansissel/software-patterns/tree/master/dont-log-secrets/ruby
|
10
|
+
define_method(:xml) { REXML::Document.new(data).root }
|
11
|
+
private :xml
|
12
|
+
end
|
13
|
+
@ticket_id = xml.attributes["ticketId"]
|
14
|
+
@parent_ticket_id = xml.attributes["parentTicketId"]
|
15
|
+
@note = xml.attributes["note"]
|
16
|
+
response = xml.elements["response"]
|
17
|
+
@description = response.attributes["description"]
|
18
|
+
@code = response.attributes["code"].to_i
|
19
|
+
message = xml.elements["message"]
|
20
|
+
@segment_number = message.attributes["segmentNumber"]
|
21
|
+
@timestamp = DateTime.strptime(message.attributes["deliveryDate"] + "+0000", '%FT%T.%LZ%z').utc
|
22
|
+
state = message.elements["state"]
|
23
|
+
@state_id = state.attributes["id"].to_i
|
24
|
+
@state_description = state.attributes["description"]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "rexml/document"
|
2
|
+
|
3
|
+
module OpenMarket
|
4
|
+
class MO
|
5
|
+
attr_reader :account_id, :carrier_id, :data, :data_coding, :destination_address, :destination_ton, :source_address, :source_ton, :ticket_id, :udhi
|
6
|
+
def initialize(data)
|
7
|
+
(class << self; self; end).class_eval do
|
8
|
+
# Defining a member variable for xml would pollute #inspect
|
9
|
+
# This solution is inspired by https://github.com/jordansissel/software-patterns/tree/master/dont-log-secrets/ruby
|
10
|
+
define_method(:xml) { REXML::Document.new(data).root }
|
11
|
+
private :xml
|
12
|
+
end
|
13
|
+
if ticket = xml.elements["ticket"]
|
14
|
+
@ticket_id = ticket.attributes["id"]
|
15
|
+
end
|
16
|
+
if account = xml.elements["account"]
|
17
|
+
@account_id = account.attributes["id"]
|
18
|
+
end
|
19
|
+
if source = xml.elements["source"]
|
20
|
+
@carrier_id = source.elements["carrier"]
|
21
|
+
@source_ton = source.elements["ton"]
|
22
|
+
@source_address = source.elements["address"]
|
23
|
+
end
|
24
|
+
if destination = xml.elements["destination"]
|
25
|
+
@destination_ton = destination.elements["ton"]
|
26
|
+
@destination_address = destination.elements["address"]
|
27
|
+
end
|
28
|
+
if option = xml.elements["option"]
|
29
|
+
@data_coding = option.attributes["datacoding"]
|
30
|
+
end
|
31
|
+
if message = xml.elements["message"]
|
32
|
+
@udhi = message.attributes["udhi"] == true
|
33
|
+
@data = message.attributes["data"]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require "rexml/document"
|
2
|
+
|
3
|
+
module OpenMarket
|
4
|
+
class Response
|
5
|
+
attr_reader :code, :description
|
6
|
+
def initialize(http_response)
|
7
|
+
(class << self; self; end).class_eval do
|
8
|
+
# Defining a member variable for xml would pollute #inspect
|
9
|
+
# This solution is inspired by https://github.com/jordansissel/software-patterns/tree/master/dont-log-secrets/ruby
|
10
|
+
define_method(:xml) do
|
11
|
+
if http_response.respond_to?(:body)
|
12
|
+
REXML::Document.new(http_response.body).root
|
13
|
+
else
|
14
|
+
REXML::Document.new(http_response.to_xml).root.elements["response"]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
private :xml
|
18
|
+
end
|
19
|
+
error = xml.elements["error"]
|
20
|
+
@code = (error.attributes["code"] || error.elements["code"].text).to_i
|
21
|
+
@description = error.attributes["description"] || error.elements["description"].text
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class CarrierLookupResponse < Response
|
26
|
+
attr_reader :country_code, :national_number, :intl_notation, :area_code, :area_code_length, :num_min_length, :num_max_length, :na_nxx, :na_line, :local_notation, :local_format, :digits_all, :digits_local, :ported, :ported_from
|
27
|
+
attr_reader :city, :country, :country_name, :estimated_latitude, :estimated_longitude, :region, :region_name, :timezone_min, :timezone_max, :zone, :zone_name
|
28
|
+
attr_reader :carrier_id, :name, :binary_length, :text_length, :unicode_length, :binary, :ems, :smart_messaging, :unicode, :wap_push
|
29
|
+
|
30
|
+
def initialize(http_response)
|
31
|
+
super
|
32
|
+
if destination = xml.elements["destination"]
|
33
|
+
@country_code = destination.attributes["country_code"].to_i
|
34
|
+
@national_number = destination.attributes["national_number"]
|
35
|
+
@intl_notation = destination.attributes["intl_notation"]
|
36
|
+
@area_code = destination.attributes["area_code"]
|
37
|
+
@area_code_length = destination.attributes["area_code_length"].to_i
|
38
|
+
@num_min_length = destination.attributes["num_min_length"].to_i
|
39
|
+
@num_max_length = destination.attributes["num_max_length"].to_i
|
40
|
+
@na_nxx = destination.attributes["na_nxx"]
|
41
|
+
@na_line = destination.attributes["na_line"]
|
42
|
+
@local_notation = destination.attributes["local_notation"]
|
43
|
+
@local_format = destination.attributes["local_format"]
|
44
|
+
@digits_all = destination.attributes["digits_all"].to_i
|
45
|
+
@digits_local = destination.attributes["digits_local"].to_i
|
46
|
+
@ported = destination.attributes["ported"] == "true"
|
47
|
+
@ported_from = destination.attributes["ported_from"]
|
48
|
+
end
|
49
|
+
if location = xml.elements["location"]
|
50
|
+
@city = location.attributes["city"]
|
51
|
+
@country = location.attributes["country"]
|
52
|
+
@country_name = location.attributes["country_name"]
|
53
|
+
@estimated_latitude = location.attributes["estimated_latitude"].to_f
|
54
|
+
@estimated_longitude = location.attributes["estimated_longitude"].to_f
|
55
|
+
@region = location.attributes["region"]
|
56
|
+
@region_name = location.attributes["region_name"]
|
57
|
+
@timezone_min = location.attributes["timezone_min"].to_i
|
58
|
+
@timezone_max= location.attributes["timezone_max"].to_i
|
59
|
+
@zone = location.attributes["zone"].to_i
|
60
|
+
@zone_name = location.attributes["zone_name"]
|
61
|
+
end
|
62
|
+
if operator = xml.elements["operator"]
|
63
|
+
@carrier_id = operator.attributes["id"].to_i
|
64
|
+
@name = operator.attributes["name"]
|
65
|
+
@binary_length = operator.attributes["binary_length"].to_i
|
66
|
+
@text_length = operator.attributes["text_length"].to_i
|
67
|
+
@unicode_length = operator.attributes["unicode_length"].to_i
|
68
|
+
@binary = operator.attributes["binary"] == "true"
|
69
|
+
@ems = operator.attributes["ems"] == "true"
|
70
|
+
@smart_messaging = operator.attributes["smart_messaging"] == "true"
|
71
|
+
@unicode = operator.attributes["unicode"] == "true"
|
72
|
+
@wap_push = operator.attributes["wap_push"] == "true"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class SendSmsResponse < Response
|
78
|
+
attr_reader :ticket_id, :carrier_id
|
79
|
+
def initialize(http_response, carrier_id)
|
80
|
+
super(http_response)
|
81
|
+
@carrier_id = carrier_id
|
82
|
+
if ticket = xml.elements["ticket"]
|
83
|
+
@ticket_id = ticket.attributes["id"]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class StatusResponse < Response
|
89
|
+
attr_reader :status_code, :status_description
|
90
|
+
def initialize(http_response)
|
91
|
+
super
|
92
|
+
if status = xml.elements["status"]
|
93
|
+
@status_code = status.attributes["code"].to_i
|
94
|
+
@status_description = status.attributes["description"]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/lib/openmarket.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "open_market"
|
data/open_market.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'open_market/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "openmarket"
|
8
|
+
spec.version = OpenMarket::VERSION
|
9
|
+
spec.authors = ["Isaac Betesh"]
|
10
|
+
spec.email = ["iybetesh@gmail.com"]
|
11
|
+
spec.summary = "Send SMS messages using the OpenMarket API"
|
12
|
+
spec.description = `cat README.md`
|
13
|
+
spec.homepage = "https://github.com/betesh/open_market"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
spec.add_development_dependency "rspec", "~> 3"
|
24
|
+
|
25
|
+
spec.add_dependency "sms_validation", "~> 0.0.2"
|
26
|
+
spec.add_dependency "httparty"
|
27
|
+
spec.add_dependency "builder"
|
28
|
+
end
|
data/spec/api_spec.rb
ADDED
@@ -0,0 +1,220 @@
|
|
1
|
+
require "open_market/api"
|
2
|
+
require "support/configuration_from_yaml"
|
3
|
+
|
4
|
+
describe OpenMarket::Api do
|
5
|
+
subject { OpenMarket::API }
|
6
|
+
|
7
|
+
describe "#carrier_lookup" do
|
8
|
+
it "should succeed without a 1 preceding the phone number" do
|
9
|
+
result = subject.carrier_lookup(phone)
|
10
|
+
expect(result).to be_a(OpenMarket::CarrierLookupResponse)
|
11
|
+
expect(result.code).to eq(0)
|
12
|
+
expect(result.description).to eq("No Error")
|
13
|
+
expect(result.carrier_id).to eq(carrier_id)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should succeed with a 1 preceding the phone number" do
|
17
|
+
result = subject.carrier_lookup("1#{phone}")
|
18
|
+
expect(result).to be_a(OpenMarket::CarrierLookupResponse)
|
19
|
+
expect(result.code).to eq(0)
|
20
|
+
expect(result.description).to eq("No Error")
|
21
|
+
expect(result.carrier_id).to eq(carrier_id)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#send_sms" do
|
26
|
+
it "should send an SMS" do
|
27
|
+
result = subject.send_sms(phone, "Test of OpenMarket API", carrier_id: carrier_id)
|
28
|
+
expect(result.code).to eq(2)
|
29
|
+
expect(result.description).to eq("Message received.")
|
30
|
+
expect(result.ticket_id).not_to be_nil
|
31
|
+
end
|
32
|
+
|
33
|
+
it "looks up the carrier_id if it is not passed as an option and returns it" do
|
34
|
+
expect(OpenMarket::Api::Http).to receive(:post).and_wrap_original do |original, *args, &block|
|
35
|
+
expect(args[0]).to eq("/wmp")
|
36
|
+
puts args[1][:body].inspect
|
37
|
+
expect(args[1][:body]).to match /\A<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><request version=\"3.0\" protocol=\"wmp\" type=\"preview\"><user agent=\"openmarket_rubygem\/SMS\/0\.0\.1\"\/><account id=\"#{id}\" password=\"#{password}\"\/><destination ton=\"1\" address=\"1#{phone}\"\/><\/request>\z/
|
38
|
+
original.call(*args, &block)
|
39
|
+
end
|
40
|
+
expect(OpenMarket::Api::Http).to receive(:post).and_wrap_original do |original, *args, &block|
|
41
|
+
expect(args[0]).to eq("/wmp")
|
42
|
+
expect(args[1][:body]).to match /\A<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><request version=\"3.0\" protocol=\"wmp\" type=\"submit\"><user agent=\"openmarket_rubygem\/SMS\/0\.0\.1\"\/><account id=\"#{id}\" password=\"#{password}\"\/><option charge_type=\"0\" program_id=\"#{program_id}\" mlc=\"0\"\/><source ton=\"3\" address=\"#{short_code}\"\/><destination ton=\"1\" address=\"1#{phone}\" carrier=\"#{carrier_id}\"\/><message text=\"Test of OpenMarket API\"\/><\/request>\z/
|
43
|
+
original.call(*args, &block)
|
44
|
+
end
|
45
|
+
result = subject.send_sms(phone, "Test of OpenMarket API")
|
46
|
+
expect(result.carrier_id).to eq(carrier_id)
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "message_length_control" do
|
50
|
+
describe "when SmsValidation.configuration.on_message_too_long is truncate" do
|
51
|
+
it "should be 1" do
|
52
|
+
SmsValidation.configuration.on_message_too_long = :truncate
|
53
|
+
expect(OpenMarket::Api::Http).to receive(:post).and_wrap_original do |original, *args, &block|
|
54
|
+
expect(args[0]).to eq("/wmp")
|
55
|
+
expect(args[1][:body]).to match /\A<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><request version=\"3.0\" protocol=\"wmp\" type=\"submit\"><user agent=\"openmarket_rubygem\/SMS\/0\.0\.1\"\/><account id=\"#{id}\" password=\"#{password}\"\/><option charge_type=\"0\" program_id=\"#{program_id}\" mlc=\"1\"\/><source ton=\"3\" address=\"#{short_code}\"\/><destination ton=\"1\" address=\"1#{phone}\" carrier=\"#{carrier_id}\"\/><message text=\"Test of OpenMarket API\"\/><\/request>\z/
|
56
|
+
original.call(*args, &block)
|
57
|
+
end
|
58
|
+
subject.send_sms(phone, "Test of OpenMarket API", carrier_id: carrier_id)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "when SmsValidation.configuration.on_message_too_long is split" do
|
63
|
+
it "should be 2" do
|
64
|
+
SmsValidation.configuration.on_message_too_long = :split
|
65
|
+
expect(OpenMarket::Api::Http).to receive(:post).and_wrap_original do |original, *args, &block|
|
66
|
+
expect(args[0]).to eq("/wmp")
|
67
|
+
expect(args[1][:body]).to match /\A<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><request version=\"3.0\" protocol=\"wmp\" type=\"submit\"><user agent=\"openmarket_rubygem\/SMS\/0\.0\.1\"\/><account id=\"#{id}\" password=\"#{password}\"\/><option charge_type=\"0\" program_id=\"#{program_id}\" mlc=\"2\"\/><source ton=\"3\" address=\"#{short_code}\"\/><destination ton=\"1\" address=\"1#{phone}\" carrier=\"#{carrier_id}\"\/><message text=\"Test of OpenMarket API\"\/><\/request>\z/
|
68
|
+
original.call(*args, &block)
|
69
|
+
end
|
70
|
+
subject.send_sms(phone, "Test of OpenMarket API", carrier_id: carrier_id)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "when SmsValidation.configuration.on_message_too_long is raise_error" do
|
75
|
+
it "should be 0" do
|
76
|
+
SmsValidation.configuration.on_message_too_long = :raise_error
|
77
|
+
expect(OpenMarket::Api::Http).to receive(:post).and_wrap_original do |original, *args, &block|
|
78
|
+
expect(args[0]).to eq("/wmp")
|
79
|
+
expect(args[1][:body]).to match /\A<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><request version=\"3.0\" protocol=\"wmp\" type=\"submit\"><user agent=\"openmarket_rubygem\/SMS\/0\.0\.1\"\/><account id=\"#{id}\" password=\"#{password}\"\/><option charge_type=\"0\" program_id=\"#{program_id}\" mlc=\"0\"\/><source ton=\"3\" address=\"#{short_code}\"\/><destination ton=\"1\" address=\"1#{phone}\" carrier=\"#{carrier_id}\"\/><message text=\"Test of OpenMarket API\"\/><\/request>\z/
|
80
|
+
original.call(*args, &block)
|
81
|
+
end
|
82
|
+
subject.send_sms(phone, "Test of OpenMarket API", carrier_id: carrier_id)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "invalid keys" do
|
88
|
+
it "should raise a gramatically correct error with 1 unknown option" do
|
89
|
+
expect{subject.send_sms(phone, "Test of OpenMarket API", carrier_id: carrier_id, unknown_option: true)}.to raise_error(OpenMarket::Api::InvalidOptions, "unknown_option is not a valid option")
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should raise a gramatically correct error with 2 unknown options" do
|
93
|
+
expect{subject.send_sms(phone, "Test of OpenMarket API", carrier_id: carrier_id, unknown_option: true, other_unknown: false)}.to raise_error(OpenMarket::Api::InvalidOptions, "unknown_option, other_unknown are not valid options")
|
94
|
+
end
|
95
|
+
|
96
|
+
it "automatically converts String keys to Symbol" do
|
97
|
+
expect{subject.send_sms(phone, "Test of OpenMarket API", "carrier_id" => carrier_id, "ticket_id_for_retry" => "ABC", "dr_url" => dr_url, "note" => "ABCDEFFF", "minutes_to_retry" => 10, "short_code" => 99998)}.not_to raise_error
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "valid keys" do
|
102
|
+
describe "carrier_id" do
|
103
|
+
let(:carrier_id) { 1000000 }
|
104
|
+
it "should be in the XML" do
|
105
|
+
expect(OpenMarket::Api::Http).to receive(:post).and_wrap_original do |original, *args, &block|
|
106
|
+
expect(args[0]).to eq("/wmp")
|
107
|
+
expect(args[1][:body]).to match /\A<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><request version=\"3.0\" protocol=\"wmp\" type=\"submit\"><user agent=\"openmarket_rubygem\/SMS\/0\.0\.1\"\/><account id=\"#{id}\" password=\"#{password}\"\/><option charge_type=\"0\" program_id=\"#{program_id}\" mlc=\"0\"\/><source ton=\"3\" address=\"#{short_code}\"\/><destination ton=\"1\" address=\"1#{phone}\" carrier=\"#{carrier_id}\"\/><message text=\"Test of OpenMarket API\"\/><\/request>\z/
|
108
|
+
original.call(*args, &block)
|
109
|
+
end
|
110
|
+
subject.send_sms(phone, "Test of OpenMarket API", carrier_id: carrier_id)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "note" do
|
115
|
+
let(:note) { "The quick brown fox jumps over the lazy dog" }
|
116
|
+
it "should be in the XML" do
|
117
|
+
expect(OpenMarket::Api::Http).to receive(:post).and_wrap_original do |original, *args, &block|
|
118
|
+
expect(args[0]).to eq("/wmp")
|
119
|
+
expect(args[1][:body]).to match /\A<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><request version=\"3.0\" protocol=\"wmp\" type=\"submit\"><user agent=\"openmarket_rubygem\/SMS\/0\.0\.1\"\/><account id=\"#{id}\" password=\"#{password}\"\/><option note=\"#{note}\" charge_type=\"0\" program_id=\"#{program_id}\" mlc=\"0\"\/><source ton=\"3\" address=\"#{short_code}\"\/><destination ton=\"1\" address=\"1#{phone}\" carrier=\"#{carrier_id}\"\/><message text=\"Test of OpenMarket API\"\/><\/request>\z/
|
120
|
+
original.call(*args, &block)
|
121
|
+
end
|
122
|
+
subject.send_sms(phone, "Test of OpenMarket API", carrier_id: carrier_id, note: note)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe "ticket_id_for_retry" do
|
127
|
+
let(:ticket_id_for_retry) { 1999998888 }
|
128
|
+
it "should be in the XML" do
|
129
|
+
expect(OpenMarket::Api::Http).to receive(:post).and_wrap_original do |original, *args, &block|
|
130
|
+
expect(args[0]).to eq("/wmp")
|
131
|
+
expect(args[1][:body]).to match /\A<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><request ticket_id_for_retry=\"#{ticket_id_for_retry}\" version=\"3.0\" protocol=\"wmp\" type=\"submit\"><user agent=\"openmarket_rubygem\/SMS\/0\.0\.1\"\/><account id=\"#{id}\" password=\"#{password}\"\/><option charge_type=\"0\" program_id=\"#{program_id}\" mlc=\"0\"\/><source ton=\"3\" address=\"#{short_code}\"\/><destination ton=\"1\" address=\"1#{phone}\" carrier=\"#{carrier_id}\"\/><message text=\"Test of OpenMarket API\"\/><\/request>\z/
|
132
|
+
original.call(*args, &block)
|
133
|
+
end
|
134
|
+
subject.send_sms(phone, "Test of OpenMarket API", carrier_id: carrier_id, ticket_id_for_retry: ticket_id_for_retry)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe "dr_url" do
|
139
|
+
let(:dr_url) { "example.com" }
|
140
|
+
it "should be in the XML" do
|
141
|
+
expect(OpenMarket::Api::Http).to receive(:post).and_wrap_original do |original, *args, &block|
|
142
|
+
expect(args[0]).to eq("/wmp")
|
143
|
+
expect(args[1][:body]).to match /\A<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><request version=\"3.0\" protocol=\"wmp\" type=\"submit\"><user agent=\"openmarket_rubygem\/SMS\/0\.0\.1\"\/><account id=\"#{id}\" password=\"#{password}\"\/><delivery receipt_requested=\"true\" url=\"#{dr_url}\"\/><option charge_type=\"0\" program_id=\"#{program_id}\" mlc=\"0\"\/><source ton=\"3\" address=\"#{short_code}\"\/><destination ton=\"1\" address=\"1#{phone}\" carrier=\"#{carrier_id}\"\/><message text=\"Test of OpenMarket API\"\/><\/request>\z/
|
144
|
+
original.call(*args, &block)
|
145
|
+
end
|
146
|
+
subject.send_sms(phone, "Test of OpenMarket API", dr_url: dr_url, carrier_id: carrier_id)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "minutes_to_retry" do
|
151
|
+
it "should be in the XML" do
|
152
|
+
expect(OpenMarket::Api::Http).to receive(:post).and_wrap_original do |original, *args, &block|
|
153
|
+
expect(args[0]).to eq("/wmp")
|
154
|
+
expect(args[1][:body]).to match /\A<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><request version=\"3.0\" protocol=\"wmp\" type=\"submit\"><user agent=\"openmarket_rubygem\/SMS\/0\.0\.1\"\/><account id=\"#{id}\" password=\"#{password}\"\/><delivery receipt_requested=\"true\" url=\"#{dr_url}\"\/><option charge_type=\"0\" program_id=\"#{program_id}\" mlc=\"0\"\/><source ton=\"3\" address=\"#{short_code}\"\/><destination ton=\"1\" address=\"1#{phone}\" carrier=\"#{carrier_id}\"\/><message validity_period=\"1080\" text=\"Test of OpenMarket API\"\/><\/request>\z/
|
155
|
+
original.call(*args, &block)
|
156
|
+
end
|
157
|
+
subject.send_sms(phone, "Test of OpenMarket API", dr_url: dr_url, carrier_id: carrier_id, minutes_to_retry: 18)
|
158
|
+
end
|
159
|
+
|
160
|
+
describe "can be a fraction of a number and is rounded to the nearest integer number of seconds" do
|
161
|
+
[19, 20, 21].each do |divisor|
|
162
|
+
describe do
|
163
|
+
it "should be in the XML" do
|
164
|
+
expect(OpenMarket::Api::Http).to receive(:post).and_wrap_original do |original, *args, &block|
|
165
|
+
expect(args[0]).to eq("/wmp")
|
166
|
+
expect(args[1][:body]).to match /\A<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><request version=\"3.0\" protocol=\"wmp\" type=\"submit\"><user agent=\"openmarket_rubygem\/SMS\/0\.0\.1\"\/><account id=\"#{id}\" password=\"#{password}\"\/><delivery receipt_requested=\"true\" url=\"#{dr_url}\"\/><option charge_type=\"0\" program_id=\"#{program_id}\" mlc=\"0\"\/><source ton=\"3\" address=\"#{short_code}\"\/><destination ton=\"1\" address=\"1#{phone}\" carrier=\"#{carrier_id}\"\/><message validity_period=\"3\" text=\"Test of OpenMarket API\"\/><\/request>\z/
|
167
|
+
original.call(*args, &block)
|
168
|
+
end
|
169
|
+
subject.send_sms(phone, "Test of OpenMarket API", dr_url: dr_url, carrier_id: carrier_id, minutes_to_retry: 1.0/divisor )
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe "short_code" do
|
177
|
+
let(:short_code) { 66666 }
|
178
|
+
it "should be in the XML" do
|
179
|
+
expect(OpenMarket::Api::Http).to receive(:post).and_wrap_original do |original, *args, &block|
|
180
|
+
expect(args[0]).to eq("/wmp")
|
181
|
+
expect(args[1][:body]).to match /\A<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><request version=\"3.0\" protocol=\"wmp\" type=\"submit\"><user agent=\"openmarket_rubygem\/SMS\/0\.0\.1\"\/><account id=\"#{id}\" password=\"#{password}\"\/><option charge_type=\"0\" program_id=\"#{program_id}\" mlc=\"0\"\/><source ton=\"3\" address=\"#{short_code}\"\/><destination ton=\"1\" address=\"1#{phone}\" carrier=\"#{carrier_id}\"\/><message text=\"Test of OpenMarket API\"\/><\/request>\z/
|
182
|
+
original.call(*args, &block)
|
183
|
+
end
|
184
|
+
subject.send_sms(phone, "Test of OpenMarket API", carrier_id: carrier_id, short_code: short_code)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
describe "#status" do
|
191
|
+
let(:sms) { subject.send_sms(phone, "Test of OpenMarket API") }
|
192
|
+
let(:ticket_id) { sms.ticket_id }
|
193
|
+
|
194
|
+
def get_status
|
195
|
+
subject.status(ticket_id)
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should look up the status of a ticket" do
|
199
|
+
status = get_status
|
200
|
+
expect(status.code).to eq(0)
|
201
|
+
expect(status.description).to eq("No Error")
|
202
|
+
expect(status.status_code).to eq(3)
|
203
|
+
expect(status.status_description).to eq("Message buffered with carrier and waiting for delivery response.")
|
204
|
+
print "Waiting for the message to be delivered..."
|
205
|
+
i = 0
|
206
|
+
SmsValidation.configuration.logger = nil
|
207
|
+
begin
|
208
|
+
sleep 1
|
209
|
+
print "."
|
210
|
+
status = get_status
|
211
|
+
break if 4 == status.status_code
|
212
|
+
i += 1
|
213
|
+
end while i < 5
|
214
|
+
expect(status.code).to eq(0)
|
215
|
+
expect(status.description).to eq("No Error")
|
216
|
+
expect(status.status_code).to eq(4)
|
217
|
+
expect(status.status_description).to eq("Message successfully delivered.")
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "support/configuration_from_yaml"
|
2
|
+
require "open_market/configuration"
|
3
|
+
|
4
|
+
describe OpenMarket::Configuration do
|
5
|
+
subject { OpenMarket.configuration }
|
6
|
+
let(:skip_open_market_configuration) { true }
|
7
|
+
|
8
|
+
[:id, :password, :program_id].each do |configuration_option|
|
9
|
+
describe "##{configuration_option}" do
|
10
|
+
it "cannot be nil" do
|
11
|
+
expect{subject.public_send("#{configuration_option}=", nil)}.to raise_error(OpenMarket::Configuration::Error, "#{configuration_option} cannot be blank")
|
12
|
+
end
|
13
|
+
|
14
|
+
it "cannot be an empty String" do
|
15
|
+
expect{subject.public_send("#{configuration_option}=", "")}.to raise_error(OpenMarket::Configuration::Error, "#{configuration_option} cannot be blank")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "cannot be a Hash" do
|
19
|
+
expect{subject.public_send("#{configuration_option}=", {})}.to raise_error(OpenMarket::Configuration::Error, "#{configuration_option} must be a String")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "must be set before accessing it" do
|
23
|
+
expect{subject.public_send(configuration_option)}.to raise_error(OpenMarket::Configuration::Error, "#{configuration_option} has not been set. Set it with `OpenMarket.configuration.#{configuration_option} = ...`")
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "when configured" do
|
27
|
+
let(:skip_open_market_configuration) { false }
|
28
|
+
|
29
|
+
it "is accessible" do
|
30
|
+
expect(subject.public_send(configuration_option)).to eq(public_send(configuration_option))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require "logger"
|
3
|
+
require "rspec/core/shared_context"
|
4
|
+
require "sms_validation"
|
5
|
+
|
6
|
+
module ConfigurationFromYaml
|
7
|
+
extend RSpec::Core::SharedContext
|
8
|
+
SECRETS = YAML::load(File.open(File.expand_path("#{__FILE__}/../secrets.yml")))
|
9
|
+
|
10
|
+
SECRETS.keys.each do |key|
|
11
|
+
let(key) { SECRETS[key] }
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:skip_open_market_configuration) { false }
|
15
|
+
|
16
|
+
before(:each) do
|
17
|
+
SmsValidation.configure do |config|
|
18
|
+
config.logger = ::Logger.new(STDOUT)
|
19
|
+
end
|
20
|
+
OpenMarket.configure do |config|
|
21
|
+
config.id, config.password, config.short_code, config.program_id = id, password, short_code, program_id
|
22
|
+
end unless skip_open_market_configuration
|
23
|
+
end
|
24
|
+
|
25
|
+
after(:each) do
|
26
|
+
OpenMarket.instance_variable_set("@configuration", nil)
|
27
|
+
SmsValidation.instance_variable_set("@configuration", nil)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
RSpec.configure do |config|
|
32
|
+
config.include ConfigurationFromYaml
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,280 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: openmarket
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Isaac Betesh
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-05-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sms_validation
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.0.2
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.0.2
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: httparty
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: builder
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: |
|
98
|
+
# OpenMarket
|
99
|
+
|
100
|
+
We use HTTParty to send SMS messages using the OpenMarket API. See USAGE below for details.
|
101
|
+
|
102
|
+
## Installation
|
103
|
+
|
104
|
+
Add this line to your application's Gemfile:
|
105
|
+
|
106
|
+
```ruby
|
107
|
+
gem 'openmarket'
|
108
|
+
```
|
109
|
+
|
110
|
+
And then execute:
|
111
|
+
|
112
|
+
$ bundle
|
113
|
+
|
114
|
+
Or install it yourself as:
|
115
|
+
|
116
|
+
$ gem install openmarket
|
117
|
+
|
118
|
+
## Usage
|
119
|
+
|
120
|
+
### Configuratiion
|
121
|
+
|
122
|
+
The openmarket gem requires you to provide an id, password, program_id and short_code. Configure them before attempting any API calls.
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
OpenMarket.configure do |config|
|
126
|
+
config.id = "000-000-000-00000"
|
127
|
+
config.password = "Re@llyL0ngR&om$tr1ng"
|
128
|
+
config.program_id = "ABC"
|
129
|
+
config.short_code = 99999 # You can override this on an individual message if necessary
|
130
|
+
end
|
131
|
+
```
|
132
|
+
|
133
|
+
Since the openmarket gem depends on sms_validation (https://github.com/betesh/sms_validation/), it is also recommended that you configure sms_validation.
|
134
|
+
openmarket uses sms_validation's logger. In a Rails environment, you will probably want to rely on the default configuration,
|
135
|
+
but outside of Rails, you will need to configure it if you want any logging:
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
SmsValidation.configure do |config|
|
139
|
+
config.logger = ::Logger.new(STDOUT)
|
140
|
+
end
|
141
|
+
```
|
142
|
+
|
143
|
+
### API calls
|
144
|
+
|
145
|
+
`OpenMarket::API` supports 3 API calls: `carrier_lookup`, `send_sms`, and `status`.
|
146
|
+
|
147
|
+
#### carrier_lookup
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
require 'openmarket'
|
151
|
+
phone = 2125551212
|
152
|
+
result = OpenMarket::API.carrier_lookup(phone)
|
153
|
+
|
154
|
+
# First, make sure the call succeeded
|
155
|
+
puts result.code # should be 0
|
156
|
+
puts result.description # should be 'No Error'
|
157
|
+
|
158
|
+
# If the call succeeded, you can check the carrier_id:
|
159
|
+
puts result.carrier_id # You are probably most interested in the carrier_id
|
160
|
+
puts result.inspect # But there are a lot of other attributes returned by this API call as well
|
161
|
+
```
|
162
|
+
|
163
|
+
#### send_sms
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
require 'openmarket'
|
167
|
+
phone = 2125551212
|
168
|
+
message = "Hello, this is a test of the OpenMarket API"
|
169
|
+
result = OpenMarket::API.send_sms(phone, message)
|
170
|
+
|
171
|
+
# First, make sure the call succeeded
|
172
|
+
puts result.code # should be 2
|
173
|
+
puts result.description # should be 'Message received.'
|
174
|
+
|
175
|
+
# Save the ticket ID for later. We'll use this to query the status of the ticket.
|
176
|
+
ticket_id = result.ticket_id
|
177
|
+
|
178
|
+
# Save the carrier ID for later. We'll use this next time we send an SMS to this number.
|
179
|
+
carrier_id = result.carrier_id
|
180
|
+
|
181
|
+
# There are some options you can pass along as well:
|
182
|
+
result = OpenMarket::API.send_sms(
|
183
|
+
phone,
|
184
|
+
message,
|
185
|
+
|
186
|
+
# If you want to receive DR's, you must pass a dr_url option. If you don't pass a URL, no DR will be sent to the default URL.
|
187
|
+
dr_url: "http://www.example.com/drs",
|
188
|
+
|
189
|
+
# It is highly recommended to pass a carrier_id. If you don't, the openmarket gem will make an extra API call to look up the carrier before sending the message.
|
190
|
+
carrier_id: carrier_id, # Remember the carrier ID we saved from the previous SMS?
|
191
|
+
|
192
|
+
# If you don't want to the short_code you configured above, provide another short_code to send to:
|
193
|
+
short_code: 33333,
|
194
|
+
|
195
|
+
# By default, OpenMarket re-attempts delivery for 3 days. To make OpenMarket give up and report it as a failure sooner, pass a number of minutes you would like to retry for:
|
196
|
+
minutes_to_retry: 120, # 2 hours
|
197
|
+
|
198
|
+
note: "Information that will be passed on to the DR",
|
199
|
+
|
200
|
+
ticket_id_for_retry: ticket_id # If this is a re-try of a failed ticket.
|
201
|
+
)
|
202
|
+
|
203
|
+
```
|
204
|
+
#### status
|
205
|
+
|
206
|
+
```ruby
|
207
|
+
require 'openmarket'
|
208
|
+
result = OpenMarket::API.status(ticket_id) # Remember the ticket ID we saved from #send_sms?
|
209
|
+
|
210
|
+
# First, make sure the call succeeded
|
211
|
+
puts result.code # should be 0
|
212
|
+
puts result.description # should be 'No Error'
|
213
|
+
|
214
|
+
# Check the result of the SMS message
|
215
|
+
puts result.status_code
|
216
|
+
puts result.status_description
|
217
|
+
|
218
|
+
```
|
219
|
+
|
220
|
+
## Contributing
|
221
|
+
|
222
|
+
1. Fork it ( https://github.com/betesh/open_market/fork )
|
223
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
224
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
225
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
226
|
+
5. Create a new Pull Request
|
227
|
+
email:
|
228
|
+
- iybetesh@gmail.com
|
229
|
+
executables: []
|
230
|
+
extensions: []
|
231
|
+
extra_rdoc_files: []
|
232
|
+
files:
|
233
|
+
- ".gitignore"
|
234
|
+
- ".rspec"
|
235
|
+
- Gemfile
|
236
|
+
- LICENSE.txt
|
237
|
+
- README.md
|
238
|
+
- Rakefile
|
239
|
+
- lib/open_market.rb
|
240
|
+
- lib/open_market/api.rb
|
241
|
+
- lib/open_market/configuration.rb
|
242
|
+
- lib/open_market/dr.rb
|
243
|
+
- lib/open_market/mo.rb
|
244
|
+
- lib/open_market/response.rb
|
245
|
+
- lib/open_market/version.rb
|
246
|
+
- lib/openmarket.rb
|
247
|
+
- open_market.gemspec
|
248
|
+
- spec/api_spec.rb
|
249
|
+
- spec/configuration_spec.rb
|
250
|
+
- spec/support/configuration_from_yaml.rb
|
251
|
+
- spec/support/secrets.yml.example
|
252
|
+
homepage: https://github.com/betesh/open_market
|
253
|
+
licenses:
|
254
|
+
- MIT
|
255
|
+
metadata: {}
|
256
|
+
post_install_message:
|
257
|
+
rdoc_options: []
|
258
|
+
require_paths:
|
259
|
+
- lib
|
260
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
261
|
+
requirements:
|
262
|
+
- - ">="
|
263
|
+
- !ruby/object:Gem::Version
|
264
|
+
version: '0'
|
265
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
266
|
+
requirements:
|
267
|
+
- - ">="
|
268
|
+
- !ruby/object:Gem::Version
|
269
|
+
version: '0'
|
270
|
+
requirements: []
|
271
|
+
rubyforge_project:
|
272
|
+
rubygems_version: 2.4.3
|
273
|
+
signing_key:
|
274
|
+
specification_version: 4
|
275
|
+
summary: Send SMS messages using the OpenMarket API
|
276
|
+
test_files:
|
277
|
+
- spec/api_spec.rb
|
278
|
+
- spec/configuration_spec.rb
|
279
|
+
- spec/support/configuration_from_yaml.rb
|
280
|
+
- spec/support/secrets.yml.example
|