clickatell 0.3.0 → 0.4.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/History.txt +9 -0
- data/Manifest.txt +4 -2
- data/README.txt +2 -6
- data/bin/sms +15 -4
- data/lib/clickatell.rb +9 -7
- data/lib/clickatell/api.rb +93 -142
- data/lib/clickatell/api/command.rb +28 -0
- data/lib/clickatell/api/command_executor.rb +31 -0
- data/lib/clickatell/api/error.rb +25 -0
- data/lib/clickatell/api/message_status.rb +26 -0
- data/lib/clickatell/utility/options.rb +4 -0
- data/lib/clickatell/version.rb +1 -1
- data/lib/core-ext/hash.rb +1 -1
- data/spec/api_spec.rb +48 -65
- data/website/index.txt +8 -2
- metadata +6 -4
- data/lib/clickatell/connection.rb +0 -62
- data/spec/connection_spec.rb +0 -33
data/History.txt
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
== 0.4.0
|
2
|
+
|
3
|
+
* Added API debug mode and --debug option to sms utility
|
4
|
+
* Restructured API classes into individual files
|
5
|
+
* Refactored command execution into a separate object (CommandExecutor).
|
6
|
+
* Major refactoring of API module - converted it to a class with API methods
|
7
|
+
implemented as instance methods. Code is much cleaner and Connection class
|
8
|
+
becomes redundant. See updated documentation.
|
9
|
+
|
1
10
|
== 0.3.0
|
2
11
|
|
3
12
|
* Display proper message status, not just the code
|
data/Manifest.txt
CHANGED
@@ -6,7 +6,10 @@ Rakefile
|
|
6
6
|
bin/sms
|
7
7
|
lib/clickatell.rb
|
8
8
|
lib/clickatell/api.rb
|
9
|
-
lib/clickatell/
|
9
|
+
lib/clickatell/api/command.rb
|
10
|
+
lib/clickatell/api/command_executor.rb
|
11
|
+
lib/clickatell/api/error.rb
|
12
|
+
lib/clickatell/api/message_status.rb
|
10
13
|
lib/clickatell/response.rb
|
11
14
|
lib/clickatell/utility.rb
|
12
15
|
lib/clickatell/utility/options.rb
|
@@ -15,7 +18,6 @@ lib/core-ext/hash.rb
|
|
15
18
|
scripts/txt2html
|
16
19
|
setup.rb
|
17
20
|
spec/api_spec.rb
|
18
|
-
spec/connection_spec.rb
|
19
21
|
spec/hash_ext_spec.rb
|
20
22
|
spec/response_spec.rb
|
21
23
|
spec/spec.opts
|
data/README.txt
CHANGED
@@ -10,12 +10,8 @@ account username and password.
|
|
10
10
|
require 'rubygems'
|
11
11
|
require 'clickatell'
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
'your_username',
|
16
|
-
'your_password'
|
17
|
-
)
|
18
|
-
connection.send_message('447771234567', 'Hello from clickatell')
|
13
|
+
api = Clickatell::API.authenticate('your_api_id', 'your_username', 'your_password')
|
14
|
+
api.send_message('447771234567', 'Hello from clickatell')
|
19
15
|
|
20
16
|
|
21
17
|
== Command-line SMS Utility
|
data/bin/sms
CHANGED
@@ -13,24 +13,30 @@ else
|
|
13
13
|
require 'clickatell/utility'
|
14
14
|
end
|
15
15
|
|
16
|
+
# parse command line options
|
16
17
|
options = Clickatell::Utility::Options.parse(ARGV)
|
17
|
-
|
18
|
+
|
19
|
+
# enable debugging if specified
|
20
|
+
Clickatell::API.debug_mode = true if options.debugging_enabled
|
21
|
+
|
22
|
+
# authenticate and load the API
|
23
|
+
api = Clickatell::API.authenticate(options.api_key, options.username, options.password)
|
18
24
|
|
19
25
|
begin
|
20
26
|
if options.show_balance
|
21
27
|
puts "Retrieving account balance..."
|
22
|
-
puts "You have #{
|
28
|
+
puts "You have #{api.account_balance} credits remaining."
|
23
29
|
exit 0
|
24
30
|
elsif options.show_status
|
25
31
|
puts "Getting status of message ##{options.message_id}."
|
26
|
-
status =
|
32
|
+
status = api.message_status(options.message_id)
|
27
33
|
puts "Status: #{Clickatell::API::MessageStatus[status]} (##{status})."
|
28
34
|
exit 0
|
29
35
|
else
|
30
36
|
puts "Sending '#{options.message}' to #{options.recipient}..."
|
31
37
|
additional_opts = {}
|
32
38
|
additional_opts[:from] = options.from if options.from
|
33
|
-
msg_id =
|
39
|
+
msg_id = api.send_message(options.recipient, options.message, additional_opts)
|
34
40
|
puts "Message sent successfully (message id: #{msg_id})."
|
35
41
|
exit 0
|
36
42
|
end
|
@@ -51,4 +57,9 @@ rescue Clickatell::API::Error => e
|
|
51
57
|
puts "Please contact the author (contact@lukeredpath.co.uk) with the above error."
|
52
58
|
exit 1
|
53
59
|
end
|
60
|
+
|
61
|
+
rescue Timeout::Error
|
62
|
+
puts "The connection the the Clickatell service timed out"
|
63
|
+
puts "Please check your network settings and try again."
|
64
|
+
exit 1
|
54
65
|
end
|
data/lib/clickatell.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
-
module
|
2
|
-
end
|
1
|
+
module Clickatelll end
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
%w( core-ext/hash
|
4
|
+
clickatell/version
|
5
|
+
clickatell/api
|
6
|
+
clickatell/response
|
7
|
+
|
8
|
+
).each do |lib|
|
9
|
+
require File.join(File.dirname(__FILE__), lib)
|
10
|
+
end
|
data/lib/clickatell/api.rb
CHANGED
@@ -1,160 +1,111 @@
|
|
1
|
-
require 'net/http'
|
2
|
-
|
3
1
|
module Clickatell
|
4
|
-
# This module provides the core implementation of the Clickatell
|
2
|
+
# This module provides the core implementation of the Clickatell
|
5
3
|
# HTTP service.
|
6
|
-
|
4
|
+
class API
|
5
|
+
attr_accessor :auth_options
|
7
6
|
|
8
7
|
class << self
|
9
|
-
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# API calls.
|
8
|
+
# Authenticates using the given credentials and returns an
|
9
|
+
# API instance with the authentication options set to use the
|
10
|
+
# resulting session_id.
|
13
11
|
def authenticate(api_id, username, password)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
)
|
19
|
-
parse_response(response)['OK']
|
20
|
-
end
|
21
|
-
|
22
|
-
# Pings the service with the specified session_id to keep the
|
23
|
-
# session alive.
|
24
|
-
def ping(session_id)
|
25
|
-
execute_command('ping', :session_id => session_id)
|
26
|
-
end
|
27
|
-
|
28
|
-
# Sends a message +message_text+ to +recipient+. Recipient
|
29
|
-
# number should have an international dialing prefix and
|
30
|
-
# no leading zeros (unless you have set a default prefix
|
31
|
-
# in your clickatell account centre).
|
32
|
-
#
|
33
|
-
# Takes a hash of auth_options to be used in this
|
34
|
-
# API call. Either api_id/username/password or session_id
|
35
|
-
# for an existing authenticated session.
|
36
|
-
#
|
37
|
-
# Additional options:
|
38
|
-
# :from - the from number/name
|
39
|
-
#
|
40
|
-
# Returns a new message ID if successful.
|
41
|
-
def send_message(recipient, message_text, auth_options, opts={})
|
42
|
-
valid_options = opts.only(:from)
|
43
|
-
response = execute_command('sendmsg', {
|
44
|
-
:to => recipient,
|
45
|
-
:text => message_text
|
46
|
-
}.merge(auth_hash(auth_options)).merge(valid_options))
|
47
|
-
parse_response(response)['ID']
|
48
|
-
end
|
49
|
-
|
50
|
-
# Returns the status of a message. Use message ID returned
|
51
|
-
# from original send_message call. See send_message() for
|
52
|
-
# auth_options.
|
53
|
-
def message_status(message_id, auth_options)
|
54
|
-
response = execute_command('querymsg', {
|
55
|
-
:apimsgid => message_id
|
56
|
-
}.merge( auth_hash(auth_options) ))
|
57
|
-
parse_response(response)['Status']
|
58
|
-
end
|
59
|
-
|
60
|
-
# Returns the number of credits remaining as a float.
|
61
|
-
# See send_message() for auth_options.
|
62
|
-
def account_balance(auth_options)
|
63
|
-
response = execute_command('getbalance', auth_hash(auth_options))
|
64
|
-
parse_response(response)['Credit'].to_f
|
65
|
-
end
|
66
|
-
|
67
|
-
protected
|
68
|
-
# Builds a command and sends it via HTTP GET.
|
69
|
-
def execute_command(command_name, parameters)
|
70
|
-
Net::HTTP.get_response(
|
71
|
-
Command.new(command_name).with_params(parameters)
|
72
|
-
)
|
73
|
-
end
|
74
|
-
|
75
|
-
def parse_response(raw_response) #:nodoc:
|
76
|
-
Clickatell::Response.parse(raw_response)
|
77
|
-
end
|
78
|
-
|
79
|
-
def auth_hash(options) #:nodoc:
|
80
|
-
if options[:session_id]
|
81
|
-
return {
|
82
|
-
:session_id => options[:session_id]
|
83
|
-
}
|
84
|
-
else
|
85
|
-
return {
|
86
|
-
:user => options[:username],
|
87
|
-
:password => options[:password],
|
88
|
-
:api_id => options[:api_key]
|
89
|
-
}
|
90
|
-
end
|
12
|
+
api = self.new
|
13
|
+
session_id = api.authenticate(api_id, username, password)
|
14
|
+
api.auth_options = { :session_id => session_id }
|
15
|
+
api
|
91
16
|
end
|
92
17
|
|
18
|
+
# Set to true to enable debugging (off by default)
|
19
|
+
attr_accessor :debug_mode
|
93
20
|
end
|
94
21
|
|
95
|
-
#
|
96
|
-
#
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
end
|
104
|
-
|
105
|
-
# Returns a URL for the given parameters (a hash).
|
106
|
-
def with_params(param_hash)
|
107
|
-
param_string = '?' + param_hash.map { |key, value| "#{key}=#{value}" }.sort.join('&')
|
108
|
-
return URI.parse(File.join(api_service_uri, @command_name + URI.encode(param_string)))
|
109
|
-
end
|
110
|
-
|
111
|
-
protected
|
112
|
-
def api_service_uri
|
113
|
-
protocol = @options[:secure] ? 'https' : 'http'
|
114
|
-
return "#{protocol}://#{API_SERVICE_HOST}/http/"
|
115
|
-
end
|
22
|
+
# Creates a new API instance using the specified +auth options+.
|
23
|
+
# +auth_options+ is a hash containing either a :session_id or
|
24
|
+
# :username, :password and :api_key.
|
25
|
+
#
|
26
|
+
# Some API calls (authenticate, ping etc.) do not require any
|
27
|
+
# +auth_options+. +auth_options+ can be updated using the accessor methods.
|
28
|
+
def initialize(auth_options={})
|
29
|
+
@auth_options = auth_options
|
116
30
|
end
|
117
31
|
|
118
|
-
#
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
32
|
+
# Authenticates using the specified credentials. Returns
|
33
|
+
# a session_id if successful which can be used in subsequent
|
34
|
+
# API calls.
|
35
|
+
def authenticate(api_id, username, password)
|
36
|
+
response = execute_command('auth',
|
37
|
+
:api_id => api_id,
|
38
|
+
:user => username,
|
39
|
+
:password => password
|
40
|
+
)
|
41
|
+
parse_response(response)['OK']
|
42
|
+
end
|
43
|
+
|
44
|
+
# Pings the service with the specified session_id to keep the
|
45
|
+
# session alive.
|
46
|
+
def ping(session_id)
|
47
|
+
execute_command('ping', :session_id => session_id)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Sends a message +message_text+ to +recipient+. Recipient
|
51
|
+
# number should have an international dialing prefix and
|
52
|
+
# no leading zeros (unless you have set a default prefix
|
53
|
+
# in your clickatell account centre).
|
54
|
+
#
|
55
|
+
# Additional options:
|
56
|
+
# :from - the from number/name
|
57
|
+
#
|
58
|
+
# Returns a new message ID if successful.
|
59
|
+
def send_message(recipient, message_text, opts={})
|
60
|
+
valid_options = opts.only(:from)
|
61
|
+
response = execute_command('sendmsg',
|
62
|
+
{:to => recipient, :text => message_text}.merge(valid_options)
|
63
|
+
)
|
64
|
+
parse_response(response)['ID']
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns the status of a message. Use message ID returned
|
68
|
+
# from original send_message call.
|
69
|
+
def message_status(message_id)
|
70
|
+
response = execute_command('querymsg', :apimsgid => message_id)
|
71
|
+
parse_response(response)['Status']
|
136
72
|
end
|
137
73
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
}
|
74
|
+
# Returns the number of credits remaining as a float.
|
75
|
+
def account_balance
|
76
|
+
response = execute_command('getbalance')
|
77
|
+
parse_response(response)['Credit'].to_f
|
78
|
+
end
|
79
|
+
|
80
|
+
protected
|
81
|
+
def execute_command(command_name, parameters={}) #:nodoc:
|
82
|
+
CommandExecutor.new(auth_hash, self.class.debug_mode).execute(command_name, parameters)
|
83
|
+
end
|
84
|
+
|
85
|
+
def parse_response(raw_response) #:nodoc:
|
86
|
+
Clickatell::Response.parse(raw_response)
|
87
|
+
end
|
153
88
|
|
154
|
-
def
|
155
|
-
|
89
|
+
def auth_hash #:nodoc:
|
90
|
+
if @auth_options[:session_id]
|
91
|
+
{ :session_id => @auth_options[:session_id] }
|
92
|
+
elsif @auth_options[:api_id]
|
93
|
+
{ :user => @auth_options[:username],
|
94
|
+
:password => @auth_options[:password],
|
95
|
+
:api_id => @auth_options[:api_key] }
|
96
|
+
else
|
97
|
+
{}
|
98
|
+
end
|
156
99
|
end
|
157
|
-
end
|
158
100
|
|
159
101
|
end
|
102
|
+
end
|
103
|
+
|
104
|
+
%w( api/command
|
105
|
+
api/command_executor
|
106
|
+
api/error
|
107
|
+
api/message_status
|
108
|
+
|
109
|
+
).each do |lib|
|
110
|
+
require File.join(File.dirname(__FILE__), lib)
|
160
111
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Clickatell
|
2
|
+
class API
|
3
|
+
|
4
|
+
# Represents a Clickatell HTTP gateway command in the form
|
5
|
+
# of a complete URL (the raw, low-level request).
|
6
|
+
class Command
|
7
|
+
API_SERVICE_HOST = 'api.clickatell.com'
|
8
|
+
|
9
|
+
def initialize(command_name, opts={})
|
10
|
+
@command_name = command_name
|
11
|
+
@options = { :secure => false }.merge(opts)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns a URL for the given parameters (a hash).
|
15
|
+
def with_params(param_hash)
|
16
|
+
param_string = '?' + param_hash.map { |key, value| "#{key}=#{value}" }.sort.join('&')
|
17
|
+
return URI.parse(File.join(api_service_uri, @command_name + URI.encode(param_string)))
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
def api_service_uri
|
22
|
+
protocol = @options[:secure] ? 'https' : 'http'
|
23
|
+
return "#{protocol}://#{API_SERVICE_HOST}/http/"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module Clickatell
|
4
|
+
class API
|
5
|
+
|
6
|
+
# Used to run commands agains the Clickatell gateway.
|
7
|
+
class CommandExecutor
|
8
|
+
def initialize(authentication_hash, debug=false)
|
9
|
+
@authentication_hash = authentication_hash
|
10
|
+
@debug = debug
|
11
|
+
end
|
12
|
+
|
13
|
+
# Builds a command object and sends it using HTTP GET.
|
14
|
+
# Will output URLs as they are requested to stdout when
|
15
|
+
# debugging is enabled.
|
16
|
+
def execute(command_name, parameters={})
|
17
|
+
request_uri = command(command_name, parameters)
|
18
|
+
puts "[debug] Sending request to #{request_uri}" if @debug
|
19
|
+
Net::HTTP.get_response(request_uri)
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
def command(command_name, parameters) #:nodoc:
|
24
|
+
Command.new(command_name).with_params(
|
25
|
+
parameters.merge(@authentication_hash)
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Clickatell
|
2
|
+
class API
|
3
|
+
|
4
|
+
# Clickatell API Error exception.
|
5
|
+
class Error < StandardError
|
6
|
+
attr_reader :code, :message
|
7
|
+
|
8
|
+
def initialize(code, message)
|
9
|
+
@code, @message = code, message
|
10
|
+
end
|
11
|
+
|
12
|
+
# Creates a new Error from a Clickatell HTTP response string
|
13
|
+
# e.g.:
|
14
|
+
#
|
15
|
+
# Error.parse("ERR: 001, Authentication error")
|
16
|
+
# # => #<Clickatell::API::Error code='001' message='Authentication error'>
|
17
|
+
def self.parse(error_string)
|
18
|
+
error_details = error_string.split(':').last.strip
|
19
|
+
code, message = error_details.split(',').map { |s| s.strip }
|
20
|
+
self.new(code, message)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Clickatell
|
2
|
+
class API
|
3
|
+
|
4
|
+
class MessageStatus
|
5
|
+
STATUS_MAP = {
|
6
|
+
1 => 'Message unknown',
|
7
|
+
2 => 'Message queued',
|
8
|
+
3 => 'Delivered to gateway',
|
9
|
+
4 => 'Received by recipient',
|
10
|
+
5 => 'Error with message',
|
11
|
+
6 => 'User cancelled messaged delivery',
|
12
|
+
7 => 'Error delivering message',
|
13
|
+
8 => 'OK',
|
14
|
+
9 => 'Routing error',
|
15
|
+
10 => 'Message expired',
|
16
|
+
11 => 'Message queued for later delivery',
|
17
|
+
12 => 'Out of credit'
|
18
|
+
}
|
19
|
+
|
20
|
+
def self.[](code)
|
21
|
+
STATUS_MAP[code]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
data/lib/clickatell/version.rb
CHANGED
data/lib/core-ext/hash.rb
CHANGED
data/spec/api_spec.rb
CHANGED
@@ -31,120 +31,103 @@ module Clickatell
|
|
31
31
|
end
|
32
32
|
|
33
33
|
describe "Command executor" do
|
34
|
-
it "should create an API command and send it via HTTP get, returning the raw http response" do
|
34
|
+
it "should create an API command with auth params and send it via HTTP get, returning the raw http response" do
|
35
|
+
executor = API::CommandExecutor.new(:session_id => '12345')
|
35
36
|
API::Command.should_receive(:new).with('cmdname').and_return(cmd=mock('command'))
|
36
|
-
cmd.should_receive(:with_params).with(:param_one => 'foo').and_return(uri=mock('uri'))
|
37
|
+
cmd.should_receive(:with_params).with(:param_one => 'foo', :session_id => '12345').and_return(uri=mock('uri'))
|
37
38
|
Net::HTTP.should_receive(:get_response).with(uri).and_return(raw_response=mock('http response'))
|
38
|
-
|
39
|
+
executor.execute('cmdname', :param_one => 'foo').should == raw_response
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
42
43
|
describe "API" do
|
44
|
+
before do
|
45
|
+
API.debug_mode = false
|
46
|
+
API::CommandExecutor.should_receive(:new).with({:session_id => '1234'}, false).and_return(@executor = mock('command executor'))
|
47
|
+
@api = API.new(:session_id => '1234')
|
48
|
+
end
|
49
|
+
|
43
50
|
it "should return session_id for successful authentication" do
|
44
|
-
|
51
|
+
@executor.should_receive(:execute).with('auth',
|
45
52
|
:api_id => '1234',
|
46
53
|
:user => 'joebloggs',
|
47
54
|
:password => 'superpass'
|
48
55
|
).and_return(response=mock('response'))
|
49
56
|
Response.should_receive(:parse).with(response).and_return('OK' => 'new_session_id')
|
50
|
-
|
57
|
+
@api.authenticate('1234', 'joebloggs', 'superpass').should == 'new_session_id'
|
51
58
|
end
|
52
59
|
|
53
60
|
it "should support ping" do
|
54
|
-
|
55
|
-
|
61
|
+
@executor.should_receive(:execute).with('ping', :session_id => 'abcdefg').and_return(response=mock('response'))
|
62
|
+
@api.ping('abcdefg').should == response
|
56
63
|
end
|
57
64
|
|
58
|
-
it "should support sending messages
|
59
|
-
|
60
|
-
:api_id => '1234',
|
61
|
-
:user => 'joebloggs',
|
62
|
-
:password => 'superpass',
|
65
|
+
it "should support sending messages, returning the message id" do
|
66
|
+
@executor.should_receive(:execute).with('sendmsg',
|
63
67
|
:to => '4477791234567',
|
64
68
|
:text => 'hello world'
|
65
69
|
).and_return(response=mock('response'))
|
66
70
|
Response.should_receive(:parse).with(response).and_return('ID' => 'message_id')
|
67
|
-
|
68
|
-
:username => 'joebloggs', :password => 'superpass', :api_key => '1234'
|
69
|
-
).should == 'message_id'
|
70
|
-
end
|
71
|
-
|
72
|
-
it "should support sending messages with pre-auth, returning the message id" do
|
73
|
-
API.should_receive(:execute_command).with('sendmsg',
|
74
|
-
:session_id => 'abcde',
|
75
|
-
:to => '4477791234567',
|
76
|
-
:text => 'hello world'
|
77
|
-
).and_return(response=mock('response'))
|
78
|
-
Response.should_receive(:parse).with(response).and_return('ID' => 'message_id')
|
79
|
-
API.send_message('4477791234567', 'hello world', :session_id => 'abcde').should == 'message_id'
|
71
|
+
@api.send_message('4477791234567', 'hello world').should == 'message_id'
|
80
72
|
end
|
81
73
|
|
82
74
|
it "should support sending messages with custom from number, returning the message id" do
|
83
|
-
|
84
|
-
:session_id => 'abcde',
|
75
|
+
@executor.should_receive(:execute).with('sendmsg',
|
85
76
|
:to => '4477791234567',
|
86
77
|
:text => 'hello world',
|
87
78
|
:from => 'LUKE'
|
88
79
|
).and_return(response=mock('response'))
|
89
80
|
Response.should_receive(:parse).with(response).and_return('ID' => 'message_id')
|
90
|
-
|
81
|
+
@api.send_message('4477791234567', 'hello world', :from => 'LUKE')
|
91
82
|
end
|
92
83
|
|
93
84
|
it "should ignore any invalid parameters when sending message" do
|
94
|
-
|
95
|
-
:session_id => 'abcde',
|
85
|
+
@executor.should_receive(:execute).with('sendmsg',
|
96
86
|
:to => '4477791234567',
|
97
87
|
:text => 'hello world',
|
98
88
|
:from => 'LUKE'
|
99
89
|
).and_return(response=mock('response'))
|
100
90
|
Response.stub!(:parse).and_return('ID' => 'foo')
|
101
|
-
|
91
|
+
@api.send_message('4477791234567', 'hello world', :from => 'LUKE', :any_old_param => 'test')
|
102
92
|
end
|
103
93
|
|
104
|
-
it "should support message status query
|
105
|
-
|
106
|
-
:api_id => '1234',
|
107
|
-
:user => 'joebloggs',
|
108
|
-
:password => 'superpass',
|
109
|
-
:apimsgid => 'messageid'
|
110
|
-
).and_return(response=mock('response'))
|
111
|
-
Response.should_receive(:parse).with(response).and_return('ID' => 'message_id', 'Status' => 'message_status')
|
112
|
-
API.message_status('messageid',
|
113
|
-
:username => 'joebloggs', :password => 'superpass', :api_key => '1234'
|
114
|
-
).should == 'message_status'
|
115
|
-
end
|
116
|
-
|
117
|
-
it "should support message status query with pre-auth" do
|
118
|
-
API.should_receive(:execute_command).with('querymsg',
|
119
|
-
:session_id => 'abcde',
|
94
|
+
it "should support message status query, returning message status" do
|
95
|
+
@executor.should_receive(:execute).with('querymsg',
|
120
96
|
:apimsgid => 'messageid'
|
121
97
|
).and_return(response=mock('response'))
|
122
98
|
Response.should_receive(:parse).with(response).and_return('ID' => 'message_id', 'Status' => 'message_status')
|
123
|
-
|
99
|
+
@api.message_status('messageid').should == 'message_status'
|
124
100
|
end
|
125
101
|
|
126
|
-
it "should support balance query
|
127
|
-
|
128
|
-
:api_id => '1234',
|
129
|
-
:user => 'joebloggs',
|
130
|
-
:password => 'superpass'
|
131
|
-
).and_return(response=mock('response'))
|
102
|
+
it "should support balance query, returning number of credits as a float" do
|
103
|
+
@executor.should_receive(:execute).with('getbalance', {}).and_return(response=mock('response'))
|
132
104
|
Response.should_receive(:parse).with(response).and_return('Credit' => '10.0')
|
133
|
-
|
134
|
-
end
|
135
|
-
|
136
|
-
it "should support balance query with pre-auth, returning number of credits as a float" do
|
137
|
-
API.should_receive(:execute_command).with('getbalance',
|
138
|
-
:session_id => 'abcde'
|
139
|
-
).and_return(response=mock('response'))
|
140
|
-
Response.should_receive(:parse).with(response).and_return('Credit' => '10.0')
|
141
|
-
API.account_balance(:session_id => 'abcde').should == 10.0
|
105
|
+
@api.account_balance.should == 10.0
|
142
106
|
end
|
143
107
|
|
144
108
|
it "should raise an API::Error if the response parser raises" do
|
145
|
-
|
109
|
+
@executor.stub!(:execute)
|
146
110
|
Response.stub!(:parse).and_raise(Clickatell::API::Error.new('', ''))
|
147
|
-
proc {
|
111
|
+
proc { @api.account_balance }.should raise_error(Clickatell::API::Error)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe API, ' when authenticating' do
|
116
|
+
it "should authenticate to retrieve a session_id and return a new API instance using that session id" do
|
117
|
+
API.stub!(:new).and_return(api=mock('api'))
|
118
|
+
api.should_receive(:authenticate).with('my_api_key', 'joebloggs', 'mypassword').and_return('new_session_id')
|
119
|
+
api.should_receive(:auth_options=).with(:session_id => 'new_session_id')
|
120
|
+
API.authenticate('my_api_key', 'joebloggs', 'mypassword')
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe API, ' with no authentication options set' do
|
125
|
+
it "should build commands with no authentication options" do
|
126
|
+
API.debug_mode = false
|
127
|
+
api = API.new
|
128
|
+
API::CommandExecutor.should_receive(:new).with({}, false).and_return(executor=mock('command executor'))
|
129
|
+
executor.stub!(:execute)
|
130
|
+
api.ping('1234')
|
148
131
|
end
|
149
132
|
end
|
150
133
|
|
data/website/index.txt
CHANGED
@@ -29,11 +29,17 @@ account username and password.
|
|
29
29
|
require 'rubygems'
|
30
30
|
require 'clickatell'
|
31
31
|
|
32
|
-
|
33
|
-
|
32
|
+
api = Clickatell::API.authenticate('your_api_id', 'your_username', 'your_password')
|
33
|
+
api.send_message('447771234567', 'Hello from clickatell')
|
34
34
|
</code></pre>
|
35
35
|
|
36
36
|
Full documentation for the API is available in the <a href="rdoc/">RDocs</a>.
|
37
|
+
|
38
|
+
For debugging purposes, the API allows you to view gateway URIs as they are requested, printed to $stdout. You can enable this by turning on +debug_mode+.
|
39
|
+
|
40
|
+
<pre><code class="ruby">
|
41
|
+
Clickatell::API.debug_mode = true
|
42
|
+
</code></pre>
|
37
43
|
|
38
44
|
h4. Command-line SMS Utility
|
39
45
|
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
|
|
3
3
|
specification_version: 1
|
4
4
|
name: clickatell
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2007-08-
|
6
|
+
version: 0.4.0
|
7
|
+
date: 2007-08-29 00:00:00 +01:00
|
8
8
|
summary: Ruby interface to the Clickatell SMS gateway service.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -37,7 +37,10 @@ files:
|
|
37
37
|
- bin/sms
|
38
38
|
- lib/clickatell.rb
|
39
39
|
- lib/clickatell/api.rb
|
40
|
-
- lib/clickatell/
|
40
|
+
- lib/clickatell/api/command.rb
|
41
|
+
- lib/clickatell/api/command_executor.rb
|
42
|
+
- lib/clickatell/api/error.rb
|
43
|
+
- lib/clickatell/api/message_status.rb
|
41
44
|
- lib/clickatell/response.rb
|
42
45
|
- lib/clickatell/utility.rb
|
43
46
|
- lib/clickatell/utility/options.rb
|
@@ -46,7 +49,6 @@ files:
|
|
46
49
|
- scripts/txt2html
|
47
50
|
- setup.rb
|
48
51
|
- spec/api_spec.rb
|
49
|
-
- spec/connection_spec.rb
|
50
52
|
- spec/hash_ext_spec.rb
|
51
53
|
- spec/response_spec.rb
|
52
54
|
- spec/spec.opts
|
@@ -1,62 +0,0 @@
|
|
1
|
-
module Clickatell
|
2
|
-
|
3
|
-
# The Connection object provides a high-level interface to the
|
4
|
-
# Clickatell API, handling authentication across multiple API
|
5
|
-
# requests.
|
6
|
-
#
|
7
|
-
# Example:
|
8
|
-
# conn = Clickatell::Connection.new('your_api_key', 'joebloggs', 'secret')
|
9
|
-
# message_id = conn.send_message('44777123456', 'This is a test message')
|
10
|
-
# status = conn.message_status(message_id)
|
11
|
-
#
|
12
|
-
# The Connection object provides all of the public methods implemented in
|
13
|
-
# Clickatell::API but handles the passing of authentication options
|
14
|
-
# automatically so it is not required to pass any authentication_option hashes
|
15
|
-
# into API methods that require them.
|
16
|
-
class Connection
|
17
|
-
|
18
|
-
# Returns the current Clickatell session ID.
|
19
|
-
attr_reader :session_id
|
20
|
-
|
21
|
-
# +api_key+: Your Clickatell API ID/key.
|
22
|
-
# +username+: Your Clickatell account username.
|
23
|
-
# +password+: Your Clickatell account password.
|
24
|
-
def initialize(api_key, username, password)
|
25
|
-
@api_key = api_key
|
26
|
-
@username = username
|
27
|
-
@password = password
|
28
|
-
end
|
29
|
-
|
30
|
-
# Manual authentication. Will create a new Clickatell session
|
31
|
-
# and store the session ID.
|
32
|
-
def authenticate!
|
33
|
-
@session_id = API.authenticate(@api_key, @username, @password)
|
34
|
-
end
|
35
|
-
|
36
|
-
protected
|
37
|
-
# Executes the given +api_method+ by delegating to the API
|
38
|
-
# module, using the current session_id for authentication.
|
39
|
-
def execute_api_call(api_method, params, additional_options)
|
40
|
-
params << {:session_id => current_session_id}
|
41
|
-
params << additional_options if additional_options
|
42
|
-
API.send(api_method, *params)
|
43
|
-
end
|
44
|
-
|
45
|
-
# Returns the current_session_id, authenticating if one doesn't exist
|
46
|
-
def current_session_id
|
47
|
-
authenticate! if session_id.nil?
|
48
|
-
session_id
|
49
|
-
end
|
50
|
-
|
51
|
-
# Dispatch any API methods to the API module.
|
52
|
-
def method_missing(method, *args, &block)
|
53
|
-
if API.respond_to?(method)
|
54
|
-
additional_options = args.pop if args.last.is_a?(Hash)
|
55
|
-
execute_api_call(method, args, additional_options)
|
56
|
-
else
|
57
|
-
super(method, args, &block)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
end
|
data/spec/connection_spec.rb
DELETED
@@ -1,33 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
-
require File.dirname(__FILE__) + '/../lib/clickatell'
|
3
|
-
|
4
|
-
module Clickatell
|
5
|
-
|
6
|
-
describe Connection, ' when unauthenticated' do
|
7
|
-
it "should authenticate and store session_id before sending command" do
|
8
|
-
connection = Connection.new('my_api_key', 'myusername', 'mypassword')
|
9
|
-
API.should_receive(:authenticate).with('my_api_key', 'myusername', 'mypassword').and_return('new_session_id')
|
10
|
-
API.should_receive(:send_message).with('4477791234567', 'hello world', :session_id => 'new_session_id')
|
11
|
-
connection.send_message('4477791234567', 'hello world')
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
describe Connection, ' when authenticated' do
|
16
|
-
before do
|
17
|
-
@connection = Connection.new('my_api_key', 'myusername', 'mypassword')
|
18
|
-
@connection.stub!(:session_id).and_return('session_id')
|
19
|
-
end
|
20
|
-
|
21
|
-
it "should send command with session_id without re-authenticating" do
|
22
|
-
API.should_receive(:authenticate).never
|
23
|
-
API.should_receive(:send_message).with('4477791234567', 'hello world', :session_id => 'session_id')
|
24
|
-
@connection.send_message('4477791234567', 'hello world')
|
25
|
-
end
|
26
|
-
|
27
|
-
it "should support API calls with additional opts, passing them after auth options" do
|
28
|
-
API.should_receive(:send_message).with('4477791234567', 'hello world', {:session_id => 'session_id'}, :from => 'LUKE')
|
29
|
-
@connection.send_message('4477791234567', 'hello world', {:from => 'LUKE'})
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|