clockworksms 1.0.0
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.
- data/Gemfile +9 -0
- data/Gemfile.lock +26 -0
- data/LICENSE +13 -0
- data/README.md +119 -0
- data/lib/clockwork.rb +14 -0
- data/lib/clockwork/api.rb +133 -0
- data/lib/clockwork/error.rb +28 -0
- data/lib/clockwork/http.rb +40 -0
- data/lib/clockwork/message_collection.rb +39 -0
- data/lib/clockwork/sms.rb +95 -0
- data/lib/clockwork/sms/response.rb +39 -0
- data/lib/clockwork/xml/credit.rb +49 -0
- data/lib/clockwork/xml/sms.rb +114 -0
- data/lib/clockwork/xml/xml.rb +17 -0
- metadata +91 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.3)
|
5
|
+
faraday (0.8.0)
|
6
|
+
multipart-post (~> 1.1)
|
7
|
+
multipart-post (1.1.5)
|
8
|
+
nokogiri (1.5.2)
|
9
|
+
rake (0.9.2.2)
|
10
|
+
rspec (2.10.0)
|
11
|
+
rspec-core (~> 2.10.0)
|
12
|
+
rspec-expectations (~> 2.10.0)
|
13
|
+
rspec-mocks (~> 2.10.0)
|
14
|
+
rspec-core (2.10.0)
|
15
|
+
rspec-expectations (2.10.0)
|
16
|
+
diff-lcs (~> 1.1.3)
|
17
|
+
rspec-mocks (2.10.1)
|
18
|
+
|
19
|
+
PLATFORMS
|
20
|
+
ruby
|
21
|
+
|
22
|
+
DEPENDENCIES
|
23
|
+
faraday
|
24
|
+
nokogiri
|
25
|
+
rake
|
26
|
+
rspec
|
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright (C) 2012, Mediaburst Limited <hello@mediaburst.co.uk>
|
2
|
+
|
3
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
4
|
+
purpose with or without fee is hereby granted, provided that the above
|
5
|
+
copyright notice and this permission notice appear in all copies.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
8
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
9
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
10
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
11
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
12
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
13
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE
|
data/README.md
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
# Clockwork SMS API Ruby Gem
|
2
|
+
|
3
|
+
## Install
|
4
|
+
|
5
|
+
Just add the following to your Gemfile:
|
6
|
+
|
7
|
+
gem 'clockworksms'
|
8
|
+
|
9
|
+
## Documentation
|
10
|
+
|
11
|
+
Full documentation is at [http://rubydoc.info/github/mediaburst/clockwork-ruby/master/frames][1]. Alternatively, run `yard doc` and open doc/index.html.
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
For more information on the available optional parameters for the API (Clockwork::API), see [here][4].
|
16
|
+
|
17
|
+
For more information on the available optional parameters for each SMS (Clockwork::SMS), see [here][5]. For more information on the response object returned from each SMS (Clockwork::SMS::Response), see [here][6].
|
18
|
+
|
19
|
+
### Send a single SMS message
|
20
|
+
|
21
|
+
require 'clockwork'
|
22
|
+
api = Clockwork::API.new( 'API_KEY_GOES_HERE' )
|
23
|
+
message = api.messages.build( :to => '441234123456', :content => 'This is a test message.' )
|
24
|
+
response = message.deliver
|
25
|
+
|
26
|
+
if response.success
|
27
|
+
puts response.message_id
|
28
|
+
else
|
29
|
+
puts response.error_code
|
30
|
+
puts response.error_description
|
31
|
+
end
|
32
|
+
|
33
|
+
### Alternative usage for sending an SMS message
|
34
|
+
|
35
|
+
require 'clockwork'
|
36
|
+
api = Clockwork::API.new( 'API_KEY_GOES_HERE' )
|
37
|
+
|
38
|
+
message = api.messages.build
|
39
|
+
message.to = '441234123456'
|
40
|
+
message.content = 'This is a test message.'
|
41
|
+
response = message.deliver
|
42
|
+
|
43
|
+
if response.success
|
44
|
+
puts response.message_id
|
45
|
+
else
|
46
|
+
puts response.error_code
|
47
|
+
puts response.error_description
|
48
|
+
end
|
49
|
+
|
50
|
+
### Send multiple SMS messages (with an optional client ID)
|
51
|
+
|
52
|
+
You should not use the `Clockwork::Message#deliver` method for each message, but instead use the `Clockwork::API#deliver` method to send multiple messages in the same API request. This will decrease load on the API and ensure your requests are processed significantly faster.
|
53
|
+
|
54
|
+
messages = [
|
55
|
+
{ :to => '441234123456', :content => 'This is a test message.', :client_id => '1' },
|
56
|
+
{ :to => '441234123456', :content => 'This is a test message 2.', :client_id => '2' },
|
57
|
+
{ :to => '441234123456', :content => 'This is a test message 3.', :client_id => '3' },
|
58
|
+
{ :to => '441234123456', :content => 'This is a test message 4.', :client_id => '4' },
|
59
|
+
{ :to => '441234123456', :content => 'This is a test message 5.', :client_id => '5' },
|
60
|
+
{ :to => '441234123456', :content => 'This is a test message 6.', :client_id => '6' }
|
61
|
+
]
|
62
|
+
|
63
|
+
require 'clockwork'
|
64
|
+
api = Clockwork::API.new( 'API_KEY_GOES_HERE' )
|
65
|
+
messages.each do |m|
|
66
|
+
api.messages.build(m)
|
67
|
+
end
|
68
|
+
|
69
|
+
responses = api.deliver_messages
|
70
|
+
responses.each do |response|
|
71
|
+
puts response.client_id
|
72
|
+
if response.success
|
73
|
+
puts response.message_id
|
74
|
+
else
|
75
|
+
puts response.error_code
|
76
|
+
puts response.error_description
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
### Check credit
|
81
|
+
|
82
|
+
require 'clockwork'
|
83
|
+
api = Clockwork::API.new( 'API_KEY_GOES_HERE' )
|
84
|
+
remaining_messages = Clockwork::API.credit
|
85
|
+
puts remaining messages # => 240
|
86
|
+
|
87
|
+
## License
|
88
|
+
|
89
|
+
This project is licensed under the ISC open-source license.
|
90
|
+
|
91
|
+
A copy of this license can be found in LICENSE.
|
92
|
+
|
93
|
+
## Contributing
|
94
|
+
|
95
|
+
If you have any feedback on this wrapper drop us an email to [hello@clockworksms.com][2].
|
96
|
+
|
97
|
+
The project is hosted on GitHub at [http://www.github.com/mediaburst/clockwork-ruby][3].
|
98
|
+
|
99
|
+
If you would like to contribute a bug fix or improvement please fork the project
|
100
|
+
and submit a pull request. Please add RSpec tests for your use case.
|
101
|
+
|
102
|
+
### Test Setup
|
103
|
+
|
104
|
+
First, create a file at spec/spec_authentication_details containing the following:
|
105
|
+
|
106
|
+
34023ada3ec0d99213f91a12a2329ba932665ed7
|
107
|
+
MyLegacyAPIUsername@mydomain.com
|
108
|
+
MyPassword
|
109
|
+
|
110
|
+
Substitute your own API key, username and password on lines 1, 2, and 3 of the file.
|
111
|
+
|
112
|
+
Then, run `rspec`.
|
113
|
+
|
114
|
+
[1]: http://rubydoc.info/github/mediaburst/clockwork-ruby/master/frames
|
115
|
+
[2]: mailto:hello@clockworksms.com
|
116
|
+
[3]: http://www.github.com/mediaburst/clockwork-ruby
|
117
|
+
[4]: http://rubydoc.info/github/mediaburst/clockwork-ruby/master/Clockwork/API
|
118
|
+
[5]: http://rubydoc.info/github/mediaburst/clockwork-ruby/master/Clockwork/SMS
|
119
|
+
[6]: http://rubydoc.info/github/mediaburst/clockwork-ruby/master/Clockwork/SMS/Response
|
data/lib/clockwork.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
lib_dir = File.expand_path(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift lib_dir unless $LOAD_PATH.include?(lib_dir)
|
3
|
+
|
4
|
+
require 'net/http'
|
5
|
+
require 'nokogiri'
|
6
|
+
|
7
|
+
require 'clockwork/error'
|
8
|
+
require 'clockwork/http'
|
9
|
+
require 'clockwork/xml/xml'
|
10
|
+
|
11
|
+
require 'clockwork/message_collection'
|
12
|
+
require 'clockwork/api'
|
13
|
+
require 'clockwork/sms'
|
14
|
+
require 'clockwork/sms/response'
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# A wrapper around the Clockwork API.
|
2
|
+
module Clockwork
|
3
|
+
|
4
|
+
# Current API wrapper version
|
5
|
+
VERSION = '1.0.0'
|
6
|
+
|
7
|
+
# @author James Inman <james@mediaburst.co.uk>
|
8
|
+
# You must create an instance of Clockwork::API to begin using the API.
|
9
|
+
class API
|
10
|
+
|
11
|
+
# URL of the SMS API send action
|
12
|
+
SMS_URL = "api.clockworksms.com/xml/send"
|
13
|
+
# URL of the SMS API check credit action
|
14
|
+
CREDIT_URL = "api.clockworksms.com/xml/credit"
|
15
|
+
|
16
|
+
# API key provided in Clockwork::API#initialize.
|
17
|
+
# @return [string]
|
18
|
+
attr_reader :api_key
|
19
|
+
|
20
|
+
# This is the number of messages to concatenate (join together).
|
21
|
+
# @raise ArgumentError - if a value less than 2 or more than 3 is passed
|
22
|
+
# @return [symbol] One of +error+, +:replace+, +:remove+
|
23
|
+
# @note Defaults to 3 if not set and Clockwork::API#long is set to +true+.
|
24
|
+
attr_reader :concat
|
25
|
+
|
26
|
+
# @!attribute from
|
27
|
+
# The from address displayed on a phone when the SMS is received. This can be either a 12 digit number or 11 characters long.
|
28
|
+
# @return [string]
|
29
|
+
# @note This can be overriden for specific Clockwork::SMS objects; if it is not set your account default will be used.
|
30
|
+
attr_accessor :from
|
31
|
+
|
32
|
+
# What to do with any invalid characters in the message content. +:error+ will raise a Clockwork::InvalidCharacterException, +:replace+ will replace a small number of common invalid characters, such as the smart quotes used by Microsoft Office with a similar match, +:remove+ will remove invalid characters.
|
33
|
+
# @raise ArgumentError - if value is not one of +:error+, +:replace+, +:remove+
|
34
|
+
# @return [symbol] One of +error+, +:replace+, +:remove+
|
35
|
+
# @note This can be overriden for specific Clockwork::SMS objects; if it is not set your account default will be used.
|
36
|
+
attr_reader :invalid_char_action
|
37
|
+
|
38
|
+
# @!attribute long
|
39
|
+
# Set to +true+ to enable long SMS. A standard text can contain 160 characters, a long SMS supports up to 459. Each recipient will cost up to 3 message credits.
|
40
|
+
# @return [boolean]
|
41
|
+
# @note This can be overriden for specific Clockwork::SMS objects; if it is not set your account default will be used.
|
42
|
+
attr_accessor :long
|
43
|
+
|
44
|
+
# @!attribute messages
|
45
|
+
# Returns a Clockwork::MessageCollection containing all built SMS messages.
|
46
|
+
# @return [Clockwork::MessageCollection]
|
47
|
+
attr_reader :messages
|
48
|
+
|
49
|
+
# Password provided in Clockwork::API#initialize.
|
50
|
+
# @return [string]
|
51
|
+
# @deprecated Use api_key instead.
|
52
|
+
attr_reader :password
|
53
|
+
|
54
|
+
# @!attribute truncate
|
55
|
+
# Set to +true+ to trim the message content to the maximum length if it is too long.
|
56
|
+
# @return [boolean]
|
57
|
+
# @note This can be overriden for specific Clockwork::SMS objects; if it is not set your account default will be used.
|
58
|
+
attr_accessor :truncate
|
59
|
+
|
60
|
+
# Whether to use SSL when connecting to the API.
|
61
|
+
# Defaults to +true+
|
62
|
+
# @return [boolean]
|
63
|
+
attr_accessor :use_ssl
|
64
|
+
|
65
|
+
# Username provided in Clockwork::API#initialize.
|
66
|
+
# @return [string]
|
67
|
+
# @deprecated Use api_key instead.
|
68
|
+
attr_reader :username
|
69
|
+
|
70
|
+
# Alias for Clockwork::API#credit to preserve backwards compatibility with original Mediaburst API.
|
71
|
+
# @deprecated Use Clockwork::API#credit. Support for Clockwork::API#get_credit will be removed in a future version of this wrapper.
|
72
|
+
def get_credit
|
73
|
+
credit
|
74
|
+
end
|
75
|
+
|
76
|
+
def invalid_char_action= symbol
|
77
|
+
raise( ArgumentError, "#{symbol} must be one of :error, :replace, :remove" ) unless [:error, :replace, :remove].include?(symbol.to_sym)
|
78
|
+
end
|
79
|
+
|
80
|
+
def concat= number
|
81
|
+
raise( ArgumentError, "#{number} must be either 2 or 3" ) unless [2, 3].include?(number.to_i)
|
82
|
+
end
|
83
|
+
|
84
|
+
# @overload initalize(api_key)
|
85
|
+
# @param [string] api_key API key, 40-character hexadecimal string
|
86
|
+
# @param [hash] options Optional hash of attributes on API
|
87
|
+
# @overload initalize(username, password)
|
88
|
+
# @param [string] username Your API username
|
89
|
+
# @param [string] password Your API password
|
90
|
+
# @param [hash] options Optional hash of attributes on API
|
91
|
+
# @deprecated Use an API key instead. Support for usernames and passwords will be removed in a future version of this wrapper.
|
92
|
+
# @raise ArgumentError - if more than 3 parameters are passed
|
93
|
+
# @raise Clockwork::Error::InvalidAPIKey - if API key is invalid
|
94
|
+
# Clockwork::API is initialized with an API key, available from http://www.mediaburst.co.uk/api.
|
95
|
+
def initialize *args
|
96
|
+
if args.size == 1 || ( args.size == 2 && args[1].kind_of?(Hash) )
|
97
|
+
raise Clockwork::Error::InvalidAPIKey unless args[0][/^[A-Fa-f0-9]{40}$/]
|
98
|
+
@api_key = args[0]
|
99
|
+
elsif args.size == 2 || ( args.size == 3 && args[2].kind_of?(Hash) )
|
100
|
+
raise ArgumentError, "You must pass both a username and password." if args[0].empty? || args[1].empty?
|
101
|
+
@username = args[0]
|
102
|
+
@password = args[1]
|
103
|
+
else
|
104
|
+
raise ArgumentError, "You must pass either an API key OR a username and password."
|
105
|
+
end
|
106
|
+
|
107
|
+
args.last.each { |k, v| instance_variable_set "@#{k}", v } if args.last.kind_of?(Hash)
|
108
|
+
|
109
|
+
@use_ssl = true if @use_ssl.nil?
|
110
|
+
@concat = 3 if @concat.nil? && @long
|
111
|
+
@messages ||= Clockwork::MessageCollection.new( :api => self )
|
112
|
+
end
|
113
|
+
|
114
|
+
# Check the remaining credit for this account.
|
115
|
+
# @raise Clockwork::Error::Authentication - if API login details are incorrect
|
116
|
+
# @return [integer] Number of messages remaining
|
117
|
+
def credit
|
118
|
+
xml = Clockwork::XML::Credit.build( self )
|
119
|
+
response = Clockwork::HTTP.post( Clockwork::API::CREDIT_URL, xml, @use_ssl )
|
120
|
+
credit = Clockwork::XML::Credit.parse( response )
|
121
|
+
end
|
122
|
+
|
123
|
+
# Deliver multiple messages created using Clockwork::API#messages.build.
|
124
|
+
# @return [array] Array of Clockwork::SMS::Response objects for messages.
|
125
|
+
def deliver
|
126
|
+
xml = Clockwork::XML::SMS.build_multiple( self.messages )
|
127
|
+
http_response = Clockwork::HTTP.post( Clockwork::API::SMS_URL, xml, @use_ssl )
|
128
|
+
responses = Clockwork::XML::SMS.parse_multiple( self.messages, http_response )
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Clockwork
|
2
|
+
|
3
|
+
# Module containing Clockwork::Error classes, all of which extend StandardError.
|
4
|
+
module Error
|
5
|
+
|
6
|
+
# @author James Inman <james@mediaburst.co.uk>
|
7
|
+
# Raised if the entered authentication details (API key or username and password) are incorrect. (Error code: 2)
|
8
|
+
class Authentication < StandardError
|
9
|
+
end
|
10
|
+
|
11
|
+
# @author James Inman <james@mediaburst.co.uk>
|
12
|
+
# Raised for all error codes not otherwise specified.
|
13
|
+
class Generic < StandardError
|
14
|
+
end
|
15
|
+
|
16
|
+
# @author James Inman <james@mediaburst.co.uk>
|
17
|
+
# Raised if a HTTP connection to the API fails.
|
18
|
+
class HTTP < StandardError
|
19
|
+
end
|
20
|
+
|
21
|
+
# @author James Inman <james@mediaburst.co.uk>
|
22
|
+
# Raised if the API key is in an invalid format.
|
23
|
+
class InvalidAPIKey < StandardError
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Clockwork
|
2
|
+
|
3
|
+
# @author James Inman <james@mediaburst.co.uk>
|
4
|
+
# Wrapper around NET/HTTP
|
5
|
+
class HTTP
|
6
|
+
|
7
|
+
# Build a HTTP POST request.
|
8
|
+
# @param [string] url URL to POST to
|
9
|
+
# @param [string] data Body of the POST request.
|
10
|
+
# @param [boolean] use_ssl Whether to use SSL when making the request.
|
11
|
+
# @return [string] XML data
|
12
|
+
def self.post url, data = '', use_ssl = true
|
13
|
+
if use_ssl
|
14
|
+
uri = URI.parse "https://#{url}"
|
15
|
+
req = Net::HTTP::Post.new( uri.path )
|
16
|
+
|
17
|
+
socket = Net::HTTP.new( uri.host, uri.port )
|
18
|
+
socket.use_ssl = true
|
19
|
+
socket.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
20
|
+
else
|
21
|
+
uri = URI.parse "http://#{url}"
|
22
|
+
req = Net::HTTP::Post.new( uri.path )
|
23
|
+
|
24
|
+
socket = Net::HTTP.new( uri.host, uri.port )
|
25
|
+
end
|
26
|
+
|
27
|
+
req.content_type = "text/xml"
|
28
|
+
req.body = data
|
29
|
+
req.add_field "User-Agent", "Clockwork Ruby Wrapper/#{Clockwork::VERSION}"
|
30
|
+
|
31
|
+
response = socket.start do |http|
|
32
|
+
http.request( req )
|
33
|
+
end
|
34
|
+
|
35
|
+
response
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Clockwork
|
2
|
+
|
3
|
+
# @author James Inman <james@mediaburst.co.uk>
|
4
|
+
# Use an instance of Clockwork::API#messages.build to create SMS messages.
|
5
|
+
class MessageCollection
|
6
|
+
|
7
|
+
# @!attribute api
|
8
|
+
# An instance of Clockwork::API.
|
9
|
+
# @return [Clockwork::API]
|
10
|
+
attr_accessor :api
|
11
|
+
|
12
|
+
# @!attribute messages
|
13
|
+
# An array of Clockwork::SMS messages.
|
14
|
+
# @return [array]
|
15
|
+
attr_accessor :messages
|
16
|
+
|
17
|
+
# @param [hash] options Hash of attributes which must include an instance of Clockwork::API
|
18
|
+
# @raise ArgumentError - if a valid instance of API is not passed as :api in options
|
19
|
+
# Create a new instance of Clockwork::MessageCollection.
|
20
|
+
def initialize options
|
21
|
+
@api = options[:api]
|
22
|
+
raise ArgumentError, "Clockwork::MessageCollection#new must include an instance of Clockwork::API as :api" unless @api.kind_of?(Clockwork::API)
|
23
|
+
|
24
|
+
@messages = []
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param [hash] params Hash of parameters as attributes on Clockwork::SMS
|
28
|
+
# @see Clockwork::SMS
|
29
|
+
# Create a new instance of Clockwork::SMS in this MessageCollection.
|
30
|
+
def build params = {}
|
31
|
+
sms = Clockwork::SMS.new({ api: @api }.merge(params))
|
32
|
+
sms.wrapper_id = @messages.count
|
33
|
+
@messages << sms
|
34
|
+
sms
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Clockwork
|
2
|
+
|
3
|
+
# @author James Inman <james@mediaburst.co.uk>
|
4
|
+
# Create an instance of Clockwork::SMS for each SMS message you want to send.
|
5
|
+
class SMS
|
6
|
+
|
7
|
+
# @!attribute api
|
8
|
+
# An instance of Clockwork::API.
|
9
|
+
# @return [Clockwork::API]
|
10
|
+
attr_accessor :api
|
11
|
+
|
12
|
+
# @!attribute content
|
13
|
+
# *REQUIRED:* The message content to send.
|
14
|
+
# @return [string]
|
15
|
+
attr_accessor :content
|
16
|
+
|
17
|
+
# @!attribute client_id
|
18
|
+
# An unique message ID specified by the connecting application, for example your database record ID. Maximum length: 50 characters.
|
19
|
+
# @return [string]
|
20
|
+
attr_accessor :client_id
|
21
|
+
|
22
|
+
# @!attribute from
|
23
|
+
# The from address displayed on a phone when the SMS is received. This can be either a 12 digit number or 11 characters long.
|
24
|
+
# @return [string]
|
25
|
+
# @note If this option is set it overrides the global option specified in Clockwork::API for this SMS, if neither option is set your account default will be used.
|
26
|
+
attr_accessor :from
|
27
|
+
|
28
|
+
# @!attribute long
|
29
|
+
# Set to +true+ to enable long SMS. A standard text can contain 160 characters, a long SMS supports up to 459. Each recipient will cost up to 3 message credits.
|
30
|
+
# @return [boolean]
|
31
|
+
# @note If this option is set it overrides the global option specified in Clockwork::API for this SMS, if neither option is set your account default will be used.
|
32
|
+
attr_accessor :long
|
33
|
+
|
34
|
+
# @!attribute truncate
|
35
|
+
# Set to +true+ to trim the message content to the maximum length if it is too long.
|
36
|
+
# @return [boolean]
|
37
|
+
# @note If this option is set it overrides the global option specified in Clockwork::API for this SMS, if neither option is set your account default will be used.
|
38
|
+
attr_accessor :truncate
|
39
|
+
|
40
|
+
# What to do with any invalid characters in the message content. +:error+ will raise a Clockwork::InvalidCharacterException, +:replace+ will replace a small number of common invalid characters, such as the smart quotes used by Microsoft Office with a similar match, +:remove+ will remove invalid characters.
|
41
|
+
# @raise ArgumentError - if value is not one of +:error+, +:replace+, +:remove+
|
42
|
+
# @return [symbol] One of +error+, +:replace+, +:remove+
|
43
|
+
# @note If this option is set it overrides the global option specified in Clockwork::API for this SMS, if neither option is set your account default will be used.
|
44
|
+
attr_reader :invalid_char_action
|
45
|
+
|
46
|
+
# @!attribute to
|
47
|
+
# *REQUIRED:* The phone number to send the SMS to in international number format (without a leading + or international dialling prefix such as 00, e.g. 441234567890).
|
48
|
+
# @return [string]
|
49
|
+
attr_accessor :to
|
50
|
+
|
51
|
+
attr_writer :wrapper_id
|
52
|
+
|
53
|
+
def invalid_char_action= symbol
|
54
|
+
raise( ArgumentError, "#{symbol} must be one of :error, :replace, :remove" ) unless [:error, :replace, :remove].include?(symbol.to_sym)
|
55
|
+
end
|
56
|
+
|
57
|
+
# @param [hash] options Optional hash of attributes on Clockwork::SMS
|
58
|
+
# Create a new SMS message.
|
59
|
+
def initialize options = {}
|
60
|
+
options.each { |k, v| instance_variable_set "@#{k}", v } if options.kind_of?(Hash)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Deliver the SMS message.
|
64
|
+
# @return [Clockwork::SMS::Response] An instance of Clockwork::SMS::Response
|
65
|
+
def deliver
|
66
|
+
xml = Clockwork::XML::SMS.build_single( self )
|
67
|
+
http_response = Clockwork::HTTP.post( Clockwork::API::SMS_URL, xml, @api.use_ssl )
|
68
|
+
response = Clockwork::XML::SMS.parse_single( self, http_response )
|
69
|
+
end
|
70
|
+
|
71
|
+
# Translate standard variable names to those needed to make an XML request. First, checks if global variables are set in Clockwork::API then overwrites with variables set in Clockwork::SMS instance.
|
72
|
+
# @return [hash] Hash of XML keys and values
|
73
|
+
def translated_attributes
|
74
|
+
attributes = {}
|
75
|
+
translations = []
|
76
|
+
translations << { :var => 'client_id', :xml_var => 'ClientID' }
|
77
|
+
translations << { :var => 'concat', :xml_var => 'Concat' }
|
78
|
+
translations << { :var => 'from', :xml_var => 'From' }
|
79
|
+
translations << { :var => 'invalid_char_action', :xml_var => 'InvalidCharAction' }
|
80
|
+
translations << { :var => 'content', :xml_var => 'Content' }
|
81
|
+
translations << { :var => 'to', :xml_var => 'To' }
|
82
|
+
translations << { :var => 'truncate', :xml_var => 'Truncate' }
|
83
|
+
translations << { :var => 'wrapper_id', :xml_var => 'WrapperID' }
|
84
|
+
|
85
|
+
translations.each do |t|
|
86
|
+
self.instance_variable_set( "@#{t[:var]}", @api.instance_variable_get( "@#{t[:var]}" ) ) if self.instance_variable_get( "@#{t[:var]}" ).nil?
|
87
|
+
attributes[ t[:xml_var] ] = self.instance_variable_get( "@#{t[:var]}" ) unless self.instance_variable_get( "@#{t[:var]}" ).nil?
|
88
|
+
end
|
89
|
+
|
90
|
+
attributes
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Clockwork
|
2
|
+
class SMS
|
3
|
+
|
4
|
+
# @author James Inman <james@mediaburst.co.uk>
|
5
|
+
# A Clockwork::SMS::Response is returned for each SMS sent by Clockwork::SMS#deliver.
|
6
|
+
class Response
|
7
|
+
|
8
|
+
# @!attribute error_code
|
9
|
+
# The error code returned if the SMS fails.
|
10
|
+
# @return [string]
|
11
|
+
attr_accessor :error_code
|
12
|
+
|
13
|
+
# @!attribute error_description
|
14
|
+
# The error description returned if the SMS fails.
|
15
|
+
# @return [string]
|
16
|
+
attr_accessor :error_description
|
17
|
+
|
18
|
+
# @!attribute message_id
|
19
|
+
# The message ID returned if the SMS is sent successfully.
|
20
|
+
# @return [string]
|
21
|
+
attr_accessor :message_id
|
22
|
+
|
23
|
+
# @!attribute message
|
24
|
+
# The instance of Clockwork::SMS relating to this response.
|
25
|
+
# @return [Clockwork::SMS]
|
26
|
+
attr_accessor :message
|
27
|
+
|
28
|
+
# @!attribute success
|
29
|
+
# +true+ if the SMS is sent successfully, +false+ otherwise.
|
30
|
+
# @return [boolean]
|
31
|
+
attr_accessor :success
|
32
|
+
|
33
|
+
def error_code
|
34
|
+
@error_code.to_i unless @error_code.nil?
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Clockwork
|
2
|
+
module XML
|
3
|
+
|
4
|
+
# @author James Inman <james@mediaburst.co.uk>
|
5
|
+
# XML building and parsing for checking credit.
|
6
|
+
class Credit
|
7
|
+
|
8
|
+
# Build the XML data to check the credit from the XML API.
|
9
|
+
# @param [Clockwork::API] api Instance of Clockwork::API
|
10
|
+
# @return [string] XML data
|
11
|
+
def self.build api
|
12
|
+
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
|
13
|
+
xml.Credit {
|
14
|
+
if api.api_key
|
15
|
+
xml.Key api.api_key
|
16
|
+
else
|
17
|
+
xml.Username api.username
|
18
|
+
xml.Password api.password
|
19
|
+
end
|
20
|
+
}
|
21
|
+
end
|
22
|
+
builder.to_xml
|
23
|
+
end
|
24
|
+
|
25
|
+
# Parse the XML response.
|
26
|
+
# @param [Net::HTTPResponse] response Instance of Net::HTTPResponse
|
27
|
+
# @raise Clockwork:HTTPError - if a connection to the Clockwork API cannot be made
|
28
|
+
# @raise Clockwork::Error::Generic - if the API returns an error code other than 2
|
29
|
+
# @raise Clockwork::Error::Authentication - if API login details are incorrect
|
30
|
+
# @return [string] Number of remaining credits
|
31
|
+
def self.parse response
|
32
|
+
if response.code.to_i == 200
|
33
|
+
doc = Nokogiri.parse( response.body )
|
34
|
+
if doc.css('ErrDesc').empty?
|
35
|
+
doc.css('Credit').inner_html.to_i
|
36
|
+
elsif doc.css('ErrNo').inner_html.to_i == 2
|
37
|
+
raise Clockwork::Error::Authentication, doc.css('ErrDesc').inner_html
|
38
|
+
else
|
39
|
+
raise Clockwork::Error::Generic, doc.css('ErrDesc').inner_html
|
40
|
+
end
|
41
|
+
else
|
42
|
+
raise Clockwork::Error::HTTP, "Could not connect to the Clockwork API to check credit."
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module Clockwork
|
2
|
+
module XML
|
3
|
+
|
4
|
+
# @author James Inman <james@mediaburst.co.uk>
|
5
|
+
# XML building and parsing for sending SMS messages.
|
6
|
+
class SMS
|
7
|
+
|
8
|
+
# Build the XML data to send a single SMS using the XML API.
|
9
|
+
# @param [Clockwork::SMS] sms Instance of Clockwork::SMS
|
10
|
+
# @return [string] XML data
|
11
|
+
def self.build_single sms
|
12
|
+
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
|
13
|
+
xml.Message {
|
14
|
+
if sms.api.api_key
|
15
|
+
xml.Key sms.api.api_key
|
16
|
+
else
|
17
|
+
xml.Username sms.api.username
|
18
|
+
xml.Password sms.api.password
|
19
|
+
end
|
20
|
+
xml.SMS {
|
21
|
+
sms.translated_attributes.each do |k, v|
|
22
|
+
xml.send "#{k}", v
|
23
|
+
end
|
24
|
+
}
|
25
|
+
}
|
26
|
+
end
|
27
|
+
builder.to_xml
|
28
|
+
end
|
29
|
+
|
30
|
+
# Build the XML data to send multiple SMS messages using the XML API.
|
31
|
+
# @param [Clockwork::MessageCollection] collection Instance of Clockwork::SMS
|
32
|
+
# @return [string] XML data
|
33
|
+
def self.build_multiple collection
|
34
|
+
builder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
|
35
|
+
xml.Message {
|
36
|
+
if collection.api.api_key
|
37
|
+
xml.Key collection.api.api_key
|
38
|
+
else
|
39
|
+
xml.Username collection.api.username
|
40
|
+
xml.Password collection.api.password
|
41
|
+
end
|
42
|
+
collection.messages.each do |sms|
|
43
|
+
xml.SMS {
|
44
|
+
sms.translated_attributes.each do |k, v|
|
45
|
+
xml.send "#{k}", v
|
46
|
+
end
|
47
|
+
}
|
48
|
+
end
|
49
|
+
}
|
50
|
+
end
|
51
|
+
builder.to_xml
|
52
|
+
end
|
53
|
+
|
54
|
+
# Parse the XML data from a single SMS response from the XML API.
|
55
|
+
# @param [Clockwork::SMS] sms Instance of Clockwork::SMS
|
56
|
+
# @param [Net::HTTPResponse] http_response Instance of Net:HTTPResponse
|
57
|
+
# @raise Clockwork:HTTPError - if a connection to the Clockwork API cannot be made
|
58
|
+
# @return [Clockwork::SMS::Response] Instance of Clockwork::SMS::Response for the message
|
59
|
+
def self.parse_single sms, http_response
|
60
|
+
response = Clockwork::SMS::Response.new
|
61
|
+
response.message = sms
|
62
|
+
|
63
|
+
if http_response.code.to_i == 200
|
64
|
+
doc = Nokogiri.parse( http_response.body )
|
65
|
+
if doc.css('ErrDesc').empty?
|
66
|
+
response.success = true
|
67
|
+
response.message_id = doc.css('MessageID').inner_html
|
68
|
+
else
|
69
|
+
response.success = false
|
70
|
+
response.error_code = doc.css('ErrNo').inner_html.to_i
|
71
|
+
response.error_description = doc.css('ErrDesc').inner_html
|
72
|
+
end
|
73
|
+
else
|
74
|
+
raise Clockwork::Error::HTTP, "Could not connect to the Clockwork API to send SMS."
|
75
|
+
end
|
76
|
+
|
77
|
+
response
|
78
|
+
end
|
79
|
+
|
80
|
+
# Parse the XML data from a multiple SMS response from the XML API.
|
81
|
+
# @param [Clockwork::MessageCollection] collection Instance of Clockwork::SMS
|
82
|
+
# @param [Net::HTTPResponse] http_response Instance of Net:HTTPResponse
|
83
|
+
# @raise Clockwork:HTTPError - if a connection to the Clockwork API cannot be made
|
84
|
+
# @return [array] Array of Clockwork::SMS::Response objects relating to the messages
|
85
|
+
def self.parse_multiple collection, http_response
|
86
|
+
responses = []
|
87
|
+
|
88
|
+
if http_response.code.to_i == 200
|
89
|
+
doc = Nokogiri.parse( http_response.body )
|
90
|
+
else
|
91
|
+
raise Clockwork::Error::HTTP, "Could not connect to the Clockwork API to send SMS."
|
92
|
+
end
|
93
|
+
|
94
|
+
doc.css('SMS_Resp').each_with_index do |sms_response, i|
|
95
|
+
response = Clockwork::SMS::Response.new
|
96
|
+
response.message = collection.messages[i]
|
97
|
+
if sms_response.css('ErrDesc').empty?
|
98
|
+
response.success = true
|
99
|
+
response.message_id = sms_response.css('MessageID').inner_html
|
100
|
+
else
|
101
|
+
response.success = false
|
102
|
+
response.error_code = sms_response.css('ErrNo').inner_html.to_i
|
103
|
+
response.error_description = sms_response.css('ErrDesc').inner_html
|
104
|
+
end
|
105
|
+
responses[sms_response.css('WrapperID').inner_html.to_i] = response
|
106
|
+
end
|
107
|
+
|
108
|
+
responses
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module Clockwork
|
4
|
+
|
5
|
+
# @author James Inman <james@mediaburst.co.uk>
|
6
|
+
# Wrapper for the XML builder/parser
|
7
|
+
module XML
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
# Require everything in this directory
|
13
|
+
dir_path = File.dirname(__FILE__)
|
14
|
+
Dir["#{dir_path}/*.rb"].each do |file|
|
15
|
+
next if file =~ /xml.rb$/
|
16
|
+
require file
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: clockworksms
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Mediaburst
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-07-18 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake-compiler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
description: Ruby Gem for the Clockwork API. Send text messages with the easy to use
|
47
|
+
SMS API from Mediaburst.
|
48
|
+
email: hello@mediaburst.co.uk
|
49
|
+
executables: []
|
50
|
+
extensions: []
|
51
|
+
extra_rdoc_files: []
|
52
|
+
files:
|
53
|
+
- lib/clockwork/api.rb
|
54
|
+
- lib/clockwork/error.rb
|
55
|
+
- lib/clockwork/http.rb
|
56
|
+
- lib/clockwork/message_collection.rb
|
57
|
+
- lib/clockwork/sms/response.rb
|
58
|
+
- lib/clockwork/sms.rb
|
59
|
+
- lib/clockwork/xml/credit.rb
|
60
|
+
- lib/clockwork/xml/sms.rb
|
61
|
+
- lib/clockwork/xml/xml.rb
|
62
|
+
- lib/clockwork.rb
|
63
|
+
- Gemfile
|
64
|
+
- Gemfile.lock
|
65
|
+
- LICENSE
|
66
|
+
- README.md
|
67
|
+
homepage: http://www.clockworksms.com/
|
68
|
+
licenses: []
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
81
|
+
requirements:
|
82
|
+
- - ! '>='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 1.8.24
|
88
|
+
signing_key:
|
89
|
+
specification_version: 3
|
90
|
+
summary: Ruby Gem for the Clockwork API.
|
91
|
+
test_files: []
|