openmarket 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|