mollie-sms 0.2.1 → 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/README.rdoc +104 -0
- data/Rakefile +10 -0
- data/VERSION +1 -1
- data/lib/mollie/sms.rb +201 -21
- data/lib/mollie/sms/test_helper.rb +173 -46
- data/mollie-sms.gemspec +4 -4
- data/rails/init.rb +1 -1
- data/spec/sms_spec.rb +3 -3
- data/spec/test_helper_spec.rb +2 -2
- metadata +7 -7
- data/README +0 -7
data/README.rdoc
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
A Ruby client that allows you to send SMS messages via
|
|
2
|
+
{http://www.mollie.nl/sms-diensten/sms-gateway Mollie.nl}.
|
|
3
|
+
|
|
4
|
+
See {Mollie::SMS} for the API documentation. Or, if you are reading this as
|
|
5
|
+
plain text, on {http://rdoc.info/projects/Fingertips/Mollie-SMS rdoc.info}.
|
|
6
|
+
|
|
7
|
+
See the Mollie.nl API
|
|
8
|
+
{http://www.mollie.nl/support/documentatie/sms-diensten/sms/http/en documentation}
|
|
9
|
+
for more info.
|
|
10
|
+
|
|
11
|
+
*Note* that it currently only does what we need, for our app, at this point in
|
|
12
|
+
time. Which means that it connects to the webservice via SSL, and only sends a
|
|
13
|
+
message to *one* recipient at a time. Finally, it assumes ActiveSupport is
|
|
14
|
+
available for XML parsing. (A patch that adds a fallback, to REXML, is much
|
|
15
|
+
appreciated.)
|
|
16
|
+
|
|
17
|
+
= Install
|
|
18
|
+
|
|
19
|
+
$ gem install mollie-sms
|
|
20
|
+
|
|
21
|
+
Or if you have a checkout of the source and have installed Jeweler:
|
|
22
|
+
|
|
23
|
+
$ rake install
|
|
24
|
+
|
|
25
|
+
= Configuration
|
|
26
|
+
|
|
27
|
+
The minimum required settings are:
|
|
28
|
+
* {Mollie::SMS.username username}
|
|
29
|
+
* {Mollie::SMS.password password}
|
|
30
|
+
* {Mollie::SMS.originator originator}
|
|
31
|
+
|
|
32
|
+
For example, a Rails initializer might look like:
|
|
33
|
+
|
|
34
|
+
module Mollie
|
|
35
|
+
SMS.username = 'Fingertips'
|
|
36
|
+
SMS.password = 'secret'
|
|
37
|
+
SMS.originator = 'fngtps.nl'
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
= Examples
|
|
41
|
+
|
|
42
|
+
== Normal usage
|
|
43
|
+
|
|
44
|
+
require 'mollie/sms'
|
|
45
|
+
|
|
46
|
+
sms = Mollie::SMS.new('+31681664814', 'You have won a bowl of chicken noodle soup!')
|
|
47
|
+
=> #<Mollie::SMS from: <fngtps.nl> to: <+31681664814> body: "You have won a bowl of chicken noodle soup!">
|
|
48
|
+
|
|
49
|
+
response = sms.deliver # => #<Mollie::SMS::Response succeeded (10) `Message successfully sent.'>
|
|
50
|
+
|
|
51
|
+
response.success? # => true
|
|
52
|
+
response.result_code # => 10
|
|
53
|
+
response.message # => "Message successfully sent."
|
|
54
|
+
|
|
55
|
+
== Test usage
|
|
56
|
+
|
|
57
|
+
require 'mollie/sms'
|
|
58
|
+
require 'mollie/sms/test_helper'
|
|
59
|
+
|
|
60
|
+
Mollie::SMS.http_failure!
|
|
61
|
+
|
|
62
|
+
response = sms.deliver # => #<Mollie::SMS::Response failed (400) `[HTTP: 400] Bad request'>
|
|
63
|
+
response.success? # => false
|
|
64
|
+
response.result_code # => 400
|
|
65
|
+
response.message # => "[HTTP: 400] Bad request"
|
|
66
|
+
|
|
67
|
+
Mollie::SMS.gateway_failure! # => #<Mollie::SMS::Response failed (20) `No username given.'>
|
|
68
|
+
|
|
69
|
+
response = sms.deliver # => #<Mollie::SMS::Response failed (20) `No username given.'>
|
|
70
|
+
response.success? # => false
|
|
71
|
+
response.result_code # => 20
|
|
72
|
+
response.message # => "No username given."
|
|
73
|
+
|
|
74
|
+
Mollie::SMS.deliveries
|
|
75
|
+
=> [#<Mollie::SMS from: <fngtps.nl> to: <+31681664814> body: "You have won a bowl of chicken noodle soup!">,
|
|
76
|
+
#<Mollie::SMS from: <fngtps.nl> to: <+31681664814> body: "You have won a bowl of chicken noodle soup!">]
|
|
77
|
+
|
|
78
|
+
= Rails
|
|
79
|
+
|
|
80
|
+
If you are using Rails and load the Mollie::SMS gem, it will automatically
|
|
81
|
+
require the test helper in test mode.
|
|
82
|
+
|
|
83
|
+
It also requires the test helper in development mode, so no actual SMS
|
|
84
|
+
messages can be send. Instead, the messages are logged to the
|
|
85
|
+
development.log.
|
|
86
|
+
|
|
87
|
+
= Contributing
|
|
88
|
+
|
|
89
|
+
Once you've made your great commits:
|
|
90
|
+
|
|
91
|
+
1. {http://help.github.com/forking Fork} Mollie-SMS
|
|
92
|
+
2. Create a topic branch
|
|
93
|
+
git checkout -b my_branch
|
|
94
|
+
3. Push to your branch
|
|
95
|
+
git push origin my_branch
|
|
96
|
+
4. Create an {http://github.com/Fingertips/Mollie-SMS/issues issue} with a link
|
|
97
|
+
to your branch
|
|
98
|
+
5. That's it!
|
|
99
|
+
|
|
100
|
+
= Copyright
|
|
101
|
+
|
|
102
|
+
Copyright (c) 2010 Eloy Duran, Fingertips <eloy@fngtps.com>
|
|
103
|
+
|
|
104
|
+
This software is MIT licensed. See {file:LICENSE} for more info.
|
data/Rakefile
CHANGED
|
@@ -5,8 +5,18 @@ task :spec do
|
|
|
5
5
|
sh "ruby ./spec/functional_sms_deliver_spec.rb"
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
+
desc "Run the specs with Kicker"
|
|
9
|
+
task :kick do
|
|
10
|
+
sh "kicker -c -e rake"
|
|
11
|
+
end
|
|
12
|
+
|
|
8
13
|
task :default => :spec
|
|
9
14
|
|
|
15
|
+
desc "Generate the docs with YARD"
|
|
16
|
+
task :doc do ||
|
|
17
|
+
sh "yardoc - README.rdoc LICENSE"
|
|
18
|
+
end
|
|
19
|
+
|
|
10
20
|
begin
|
|
11
21
|
require 'rubygems'
|
|
12
22
|
require 'jeweler'
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
1.0.0
|
data/lib/mollie/sms.rb
CHANGED
|
@@ -8,10 +8,56 @@ rescue LoadError
|
|
|
8
8
|
end
|
|
9
9
|
require "active_support"
|
|
10
10
|
|
|
11
|
+
# The namespace for the Mollie.nl webservices.
|
|
12
|
+
#
|
|
13
|
+
# @see Mollie::SMS
|
|
11
14
|
module Mollie
|
|
15
|
+
# A class that allows you to send SMS messages through the Mollie.nl SMS
|
|
16
|
+
# webservice.
|
|
17
|
+
#
|
|
18
|
+
# See the {file:README.rdoc README} for examples on how to use this.
|
|
19
|
+
#
|
|
12
20
|
class SMS
|
|
21
|
+
# A collection of exception classes raised by Mollie::SMS.
|
|
22
|
+
module Exceptions
|
|
23
|
+
# The base class for Mollie::SMS exceptions.
|
|
24
|
+
class StandardError < ::StandardError; end
|
|
25
|
+
|
|
26
|
+
# The exception class which is used to indicate a validation error of one
|
|
27
|
+
# of the {SMS#params parameters} that would be send to the gateway.
|
|
28
|
+
class ValidationError < StandardError; end
|
|
29
|
+
|
|
30
|
+
# The exception class which is used to indicate a delivery failure, when
|
|
31
|
+
# the {SMS#deliver!} method is used and delivery fails.
|
|
32
|
+
class DeliveryFailure < StandardError
|
|
33
|
+
# @return [SMS] The Mollie::SMS instance.
|
|
34
|
+
attr_reader :sms
|
|
35
|
+
|
|
36
|
+
# @return [Response] The Mollie::SMS::Response instance.
|
|
37
|
+
attr_reader :response
|
|
38
|
+
|
|
39
|
+
# @param [SMS] sms The Mollie::SMS instance.
|
|
40
|
+
# @param [Response] response The Mollie::SMS::Response instance.
|
|
41
|
+
def initialize(sms, response)
|
|
42
|
+
@sms, @response = sms, response
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @return [String] A string representation of the exception.
|
|
46
|
+
def message
|
|
47
|
+
"(#{@response.message}) #{@sms.to_s}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# The SSL URI to which the parameters of a SMS are posted.
|
|
53
|
+
#
|
|
54
|
+
# Note that the certificate is *not* verified.
|
|
13
55
|
GATEWAY_URI = URI.parse("https://secure.mollie.nl/xml/sms")
|
|
14
56
|
|
|
57
|
+
# The possible values that indicate which {SMS.gateway= SMS gateway} should
|
|
58
|
+
# be used.
|
|
59
|
+
#
|
|
60
|
+
# @see http://www.mollie.nl/sms-diensten/sms-gateway/gateways
|
|
15
61
|
GATEWAYS = {
|
|
16
62
|
'basic' => '2',
|
|
17
63
|
'business' => '4',
|
|
@@ -19,31 +65,69 @@ module Mollie
|
|
|
19
65
|
'landline' => '8'
|
|
20
66
|
}
|
|
21
67
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class MissingRequiredParam < StandardError; end
|
|
25
|
-
|
|
26
|
-
class DeliveryFailure < StandardError
|
|
27
|
-
attr_reader :sms, :response
|
|
28
|
-
|
|
29
|
-
def initialize(sms, response)
|
|
30
|
-
@sms, @response = sms, response
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def message
|
|
34
|
-
"(#{@response.message}) #{@sms.to_s}"
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
68
|
+
# A list of paramaters that *must* to be included in the
|
|
69
|
+
# {SMS#params parameters} send to the gateway.
|
|
38
70
|
REQUIRED_PARAMS = %w{ username md5_password originator gateway charset type recipients message }
|
|
39
71
|
|
|
40
72
|
class << self
|
|
41
|
-
|
|
73
|
+
# @return [String] Your username for the Mollie.nl SMS webservice.
|
|
74
|
+
attr_accessor :username
|
|
42
75
|
|
|
76
|
+
# @return [String] A MD5 hashed version of your password for the
|
|
77
|
+
# Mollie.nl SMS webservice.
|
|
78
|
+
attr_reader :password
|
|
43
79
|
def password=(password)
|
|
44
80
|
@password = Digest::MD5.hexdigest(password)
|
|
45
81
|
end
|
|
46
82
|
|
|
83
|
+
# The number, or display name, that will be used to indicate the
|
|
84
|
+
# originator of a message.
|
|
85
|
+
#
|
|
86
|
+
# It should be upto either fourteen numerical characters, or eleven
|
|
87
|
+
# alphanumerical characters.
|
|
88
|
+
#
|
|
89
|
+
# @see SMS#validate_params!
|
|
90
|
+
#
|
|
91
|
+
# @return [String] The originator
|
|
92
|
+
attr_accessor :originator
|
|
93
|
+
|
|
94
|
+
# @return [String] A character set name, describing the message’s body
|
|
95
|
+
# encoding. Defaults to ‘UTF-8’.
|
|
96
|
+
attr_accessor :charset
|
|
97
|
+
|
|
98
|
+
# The type of messages that will be send. Possible values are:
|
|
99
|
+
# * normal
|
|
100
|
+
# * wappush
|
|
101
|
+
# * vcard
|
|
102
|
+
# * flash
|
|
103
|
+
# * binary
|
|
104
|
+
# * long
|
|
105
|
+
#
|
|
106
|
+
# Defaults to ‘normal’
|
|
107
|
+
#
|
|
108
|
+
# @return [String] The message type.
|
|
109
|
+
attr_accessor :type
|
|
110
|
+
|
|
111
|
+
# The gateway that should be used to send messages. Possible values are:
|
|
112
|
+
# * {GATEWAYS GATEWAYS['basic']}
|
|
113
|
+
# * {GATEWAYS GATEWAYS['business']}
|
|
114
|
+
# * {GATEWAYS GATEWAYS['business+']}
|
|
115
|
+
# * {GATEWAYS GATEWAYS['landline']}
|
|
116
|
+
#
|
|
117
|
+
# Defaults to ‘basic’.
|
|
118
|
+
#
|
|
119
|
+
# @see http://www.mollie.nl/sms-diensten/sms-gateway/gateways
|
|
120
|
+
#
|
|
121
|
+
# @return [String] The gateway ID.
|
|
122
|
+
attr_accessor :gateway
|
|
123
|
+
|
|
124
|
+
# Returns the default parameters that will be we merged with each
|
|
125
|
+
# instance’s params.
|
|
126
|
+
#
|
|
127
|
+
# This includes +username+, +md5_password+, +originator+, +gateway+,
|
|
128
|
+
# +charset+, and +type+.
|
|
129
|
+
#
|
|
130
|
+
# @return [Hash]
|
|
47
131
|
def default_params
|
|
48
132
|
{
|
|
49
133
|
'username' => @username,
|
|
@@ -60,42 +144,78 @@ module Mollie
|
|
|
60
144
|
self.type = 'normal'
|
|
61
145
|
self.gateway = GATEWAYS['basic']
|
|
62
146
|
|
|
147
|
+
# @return [Hash] The parameters that will be send to the gateway.
|
|
63
148
|
attr_reader :params
|
|
64
149
|
|
|
150
|
+
# Initializes a new Mollie::SMS instance.
|
|
151
|
+
#
|
|
152
|
+
# You can either specify the recipient’s telephone number and message
|
|
153
|
+
# body here, or later on through the accessors for these attributes.
|
|
154
|
+
#
|
|
155
|
+
# @param [String] telephone_number The recipient’s telephone number.
|
|
156
|
+
#
|
|
157
|
+
# @param [String] body The message body.
|
|
158
|
+
#
|
|
159
|
+
# @param [Hash] extra_params Optional parameters that are to be merged with
|
|
160
|
+
# the {SMS.default_params default parameters}.
|
|
65
161
|
def initialize(telephone_number = nil, body = nil, extra_params = {})
|
|
66
162
|
@params = self.class.default_params.merge(extra_params)
|
|
67
163
|
self.telephone_number = telephone_number if telephone_number
|
|
68
164
|
self.body = body if body
|
|
69
165
|
end
|
|
70
166
|
|
|
167
|
+
# @return [String] The recipient’s telephone number.
|
|
71
168
|
def telephone_number
|
|
72
169
|
@params['recipients']
|
|
73
170
|
end
|
|
74
171
|
|
|
172
|
+
# Assigns the recipient’s telephone number.
|
|
173
|
+
#
|
|
174
|
+
# @param [String] telephone_number The recipient’s telephone number.
|
|
175
|
+
# @return [String] The recipient’s telephone number.
|
|
75
176
|
def telephone_number=(telephone_number)
|
|
76
177
|
@params['recipients'] = telephone_number
|
|
77
178
|
end
|
|
78
179
|
|
|
180
|
+
# @return [String] The message body.
|
|
79
181
|
def body
|
|
80
182
|
@params['message']
|
|
81
183
|
end
|
|
82
184
|
|
|
185
|
+
# Assigns the message’s body.
|
|
186
|
+
#
|
|
187
|
+
# @param [String] body The message’s body.
|
|
188
|
+
# @return [String] The message’s body.
|
|
83
189
|
def body=(body)
|
|
84
190
|
@params['message'] = body
|
|
85
191
|
end
|
|
86
192
|
|
|
193
|
+
# Compares whether or not this and the +other+ Mollie::SMS instance are
|
|
194
|
+
# equal in recipient, body, and other parameters.
|
|
195
|
+
#
|
|
196
|
+
# @param [SMS] other The Mollie::SMS instance to compare against.
|
|
197
|
+
# @return [Boolean]
|
|
87
198
|
def ==(other)
|
|
88
199
|
other.is_a?(SMS) && other.params == params
|
|
89
200
|
end
|
|
90
201
|
|
|
202
|
+
# @return [String] A string representation of this instance.
|
|
91
203
|
def to_s
|
|
92
204
|
%{from: <#{params['originator']}> to: <#{telephone_number}> body: "#{body}"}
|
|
93
205
|
end
|
|
94
206
|
|
|
207
|
+
# @return [String] A `inspect' string representation of this instance.
|
|
95
208
|
def inspect
|
|
96
209
|
%{#<#{self.class.name} #{to_s}>}
|
|
97
210
|
end
|
|
98
211
|
|
|
212
|
+
# Posts the {#params parameters} to the gateway, through SSL.
|
|
213
|
+
#
|
|
214
|
+
# The params are validated before attempting to post them.
|
|
215
|
+
# @see #validate_params!
|
|
216
|
+
#
|
|
217
|
+
# @return [Response] A response object which encapsulates the result of the
|
|
218
|
+
# request.
|
|
99
219
|
def deliver
|
|
100
220
|
validate_params!
|
|
101
221
|
|
|
@@ -103,60 +223,120 @@ module Mollie
|
|
|
103
223
|
post.form_data = params
|
|
104
224
|
request = Net::HTTP.new(GATEWAY_URI.host, GATEWAY_URI.port)
|
|
105
225
|
request.use_ssl = true
|
|
226
|
+
request.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
|
106
227
|
request.start do |http|
|
|
107
228
|
response = http.request(post)
|
|
108
229
|
Response.new(response)
|
|
109
230
|
end
|
|
110
231
|
end
|
|
111
232
|
|
|
233
|
+
# Posts the {#params parameters} through {#deliver}, but raises a
|
|
234
|
+
# DeliveryFailure in case the request fails.
|
|
235
|
+
#
|
|
236
|
+
# This happens if an HTTP error occurs, or the gateway didn’t accept the
|
|
237
|
+
# {#params parameters}.
|
|
238
|
+
#
|
|
239
|
+
# @return [Response] Upon success, a response object which encapsulates the
|
|
240
|
+
# result of the request.
|
|
241
|
+
#
|
|
242
|
+
# @raise [DeliveryFailure] An exception which encapsulates this {SMS SMS}
|
|
243
|
+
# instance and the {Response} object.
|
|
112
244
|
def deliver!
|
|
113
245
|
response = deliver
|
|
114
|
-
raise DeliveryFailure.new(self, response) unless response.success?
|
|
246
|
+
raise Exceptions::DeliveryFailure.new(self, response) unless response.success?
|
|
115
247
|
response
|
|
116
248
|
end
|
|
117
249
|
|
|
250
|
+
# Checks if all {REQUIRED_PARAMS required parameters} are present and if
|
|
251
|
+
# the {SMS.originator} is of the right size.
|
|
252
|
+
#
|
|
253
|
+
# @see SMS.originator
|
|
254
|
+
#
|
|
255
|
+
# @raise [ValidationError] If any of the validations fail.
|
|
256
|
+
#
|
|
257
|
+
# @return [nil]
|
|
118
258
|
def validate_params!
|
|
119
259
|
params.slice(*REQUIRED_PARAMS).each do |key, value|
|
|
120
|
-
raise
|
|
260
|
+
raise Exceptions::ValidationError, "The required parameter `#{key}' is missing." if value.blank?
|
|
121
261
|
end
|
|
122
262
|
|
|
123
263
|
originator = params['originator']
|
|
124
264
|
if originator =~ /^\d+$/
|
|
125
265
|
if originator.size > 14
|
|
126
|
-
raise ValidationError, "Originator may have a maximimun of 14 numerical characters."
|
|
266
|
+
raise Exceptions::ValidationError, "Originator may have a maximimun of 14 numerical characters."
|
|
127
267
|
end
|
|
128
268
|
elsif originator.size > 11
|
|
129
|
-
raise ValidationError, "Originator may have a maximimun of 11 alphanumerical characters."
|
|
269
|
+
raise Exceptions::ValidationError, "Originator may have a maximimun of 11 alphanumerical characters."
|
|
130
270
|
end
|
|
131
271
|
end
|
|
132
272
|
|
|
273
|
+
# This class encapsulates the HTTP response and the response from the
|
|
274
|
+
# gateway. Put shortly, instances of this class return whether or not a SMS
|
|
275
|
+
# message has been delivered.
|
|
133
276
|
class Response
|
|
277
|
+
# @return [Net::HTTPResponse] The raw HTTP response object.
|
|
134
278
|
attr_reader :http_response
|
|
135
279
|
|
|
280
|
+
# Initializes a new Mollie::SMS::Response instance.
|
|
281
|
+
#
|
|
282
|
+
# @param [Net::HTTPResponse] http_response The HTTP response object.
|
|
136
283
|
def initialize(http_response)
|
|
137
284
|
@http_response = http_response
|
|
138
285
|
end
|
|
139
286
|
|
|
287
|
+
# @return [Hash] The response parameters from the gateway. Or an empty
|
|
288
|
+
# Hash if a HTTP error occurred.
|
|
140
289
|
def params
|
|
141
290
|
@params ||= http_failure? ? {} : Hash.from_xml(@http_response.read_body)['response']['item']
|
|
142
291
|
end
|
|
143
292
|
|
|
293
|
+
# Upon success, returns the result code from the gateway. Otherwise the
|
|
294
|
+
# HTTP response code.
|
|
295
|
+
#
|
|
296
|
+
# The possible gateway result codes are:
|
|
297
|
+
# * 10 - message sent
|
|
298
|
+
# * 20 - no ‘username’
|
|
299
|
+
# * 21 - no ‘password’
|
|
300
|
+
# * 22 - no, or incorrect, ‘originator’
|
|
301
|
+
# * 23 - no ‘recipients’
|
|
302
|
+
# * 24 - no ‘message’
|
|
303
|
+
# * 25 - incorrect ‘recipients’
|
|
304
|
+
# * 26 - incorrect ‘originator’
|
|
305
|
+
# * 27 - incorrect ‘message’
|
|
306
|
+
# * 28 - charset failure
|
|
307
|
+
# * 29 - parameter failure
|
|
308
|
+
# * 30 - incorrect ‘username’ or ‘password’
|
|
309
|
+
# * 31 - not enough credits to send message
|
|
310
|
+
# * 38 - binary UDH parameter misformed
|
|
311
|
+
# * 39 - ‘deliverydate’ format is not correct
|
|
312
|
+
# * 98 - gateway unreachable
|
|
313
|
+
# * 99 - unknown error
|
|
314
|
+
#
|
|
315
|
+
# @return [Integer] The result code from the gateway or HTTP response
|
|
316
|
+
# code.
|
|
144
317
|
def result_code
|
|
145
318
|
(http_failure? ? @http_response.code : params['resultcode']).to_i
|
|
146
319
|
end
|
|
147
320
|
|
|
321
|
+
# @return [String] The message from the gateway, or the HTTP message in
|
|
322
|
+
# case of a HTTP error.
|
|
323
|
+
#
|
|
324
|
+
# @see #result_code #result_code for a list of possible messages.
|
|
148
325
|
def message
|
|
149
326
|
http_failure? ? "[HTTP: #{@http_response.code}] #{@http_response.message}" : params['resultmessage']
|
|
150
327
|
end
|
|
151
328
|
|
|
329
|
+
# @return [Boolean] Whether or not the SMS message has been delivered.
|
|
152
330
|
def success?
|
|
153
331
|
!http_failure? && params['success'] == 'true'
|
|
154
332
|
end
|
|
155
333
|
|
|
334
|
+
# @return [Boolean] Whether or not the HTTP request was a success.
|
|
156
335
|
def http_failure?
|
|
157
336
|
!@http_response.is_a?(Net::HTTPSuccess)
|
|
158
337
|
end
|
|
159
338
|
|
|
339
|
+
# @return [String] A `inspect' string representation of this instance.
|
|
160
340
|
def inspect
|
|
161
341
|
"#<#{self.class.name} #{ success? ? 'succeeded' : 'failed' } (#{result_code}) `#{message}'>"
|
|
162
342
|
end
|
|
@@ -1,44 +1,13 @@
|
|
|
1
1
|
module Mollie
|
|
2
2
|
class SMS
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
success!
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def self.success!
|
|
13
|
-
http_response = Net::HTTPOK.new('1.1', '200', 'OK')
|
|
14
|
-
http_response.add_field('Content-type', 'application/xml')
|
|
15
|
-
def http_response.read_body; TestHelper::SUCCESS_BODY; end
|
|
16
|
-
@stubbed_response = Mollie::SMS::Response.new(http_response)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def self.gateway_failure!
|
|
20
|
-
http_response = Net::HTTPOK.new('1.1', '200', 'OK')
|
|
21
|
-
http_response.add_field('Content-type', 'application/xml')
|
|
22
|
-
def http_response.read_body; TestHelper::FAILURE_BODY; end
|
|
23
|
-
@stubbed_response = Mollie::SMS::Response.new(http_response)
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def self.http_failure!
|
|
27
|
-
@stubbed_response = Mollie::SMS::Response.new(Net::HTTPBadRequest.new('1.1', '400', 'Bad request'))
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def self.stubbed_response
|
|
31
|
-
@stubbed_response || success!
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def deliver
|
|
35
|
-
validate_params!
|
|
36
|
-
self.class.deliveries << self
|
|
37
|
-
self.class.stubbed_response
|
|
38
|
-
end
|
|
39
|
-
|
|
3
|
+
# A collection of helpers for testing the delivery of SMS messages.
|
|
4
|
+
#
|
|
5
|
+
# This includes:
|
|
6
|
+
# * a couple of Test::Unit {Mollie::SMS::TestHelper::Assertions assertions}
|
|
7
|
+
# * {Mollie::SMS::TestHelper::SMSExt Mollie::SMS} class extensions and
|
|
8
|
+
# overrides
|
|
40
9
|
module TestHelper
|
|
41
|
-
|
|
10
|
+
SUCCESS_BODY = %{
|
|
42
11
|
<?xml version="1.0" ?>
|
|
43
12
|
<response>
|
|
44
13
|
<item type="sms">
|
|
@@ -49,7 +18,7 @@ module Mollie
|
|
|
49
18
|
</item>
|
|
50
19
|
</response>}
|
|
51
20
|
|
|
52
|
-
|
|
21
|
+
FAILURE_BODY = %{
|
|
53
22
|
<?xml version="1.0"?>
|
|
54
23
|
<response>
|
|
55
24
|
<item type="sms">
|
|
@@ -60,17 +29,175 @@ module Mollie
|
|
|
60
29
|
</item>
|
|
61
30
|
</response>}
|
|
62
31
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
32
|
+
# A couple of Test::Unit assertions, to test the amount of sent messages.
|
|
33
|
+
module Assertions
|
|
34
|
+
# Asserts that a specific number of SMS messages have been sent, for the
|
|
35
|
+
# duration of the given block.
|
|
36
|
+
#
|
|
37
|
+
# def test_invitation_message_is_sent
|
|
38
|
+
# assert_sms_messages(1) do
|
|
39
|
+
# Account.create(:telephone_number => "+31621212121")
|
|
40
|
+
# end
|
|
41
|
+
# end
|
|
42
|
+
#
|
|
43
|
+
# @yield The context that will be used to check the number of sent
|
|
44
|
+
# messages.
|
|
45
|
+
#
|
|
46
|
+
# @return [nil]
|
|
47
|
+
#
|
|
48
|
+
# @see Mollie::SMS::TestHelper::SMSExt::ClassMethods#deliveries
|
|
49
|
+
# Mollie::SMS.deliveries
|
|
50
|
+
def assert_sms_messages(number_of_messages)
|
|
51
|
+
before = Mollie::SMS.deliveries.length
|
|
52
|
+
yield
|
|
53
|
+
diff = Mollie::SMS.deliveries.length - before
|
|
54
|
+
assert(diff == number_of_messages, "expected `#{number_of_messages}' SMS messages to be sent, actually sent `#{diff}'")
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Asserts that *no* SMS messages have been sent, for the duration of the
|
|
58
|
+
# given block.
|
|
59
|
+
#
|
|
60
|
+
# def test_no_invitation_message_is_sent_when_account_is_invalid
|
|
61
|
+
# assert_no_sms_messages do
|
|
62
|
+
# Account.create(:telephone_number => "invalid")
|
|
63
|
+
# end
|
|
64
|
+
# end
|
|
65
|
+
#
|
|
66
|
+
# @yield The context that will be used to check the number of sent
|
|
67
|
+
# messages.
|
|
68
|
+
#
|
|
69
|
+
# @return [nil]
|
|
70
|
+
#
|
|
71
|
+
# @see Mollie::SMS::TestHelper::SMSExt::ClassMethods#deliveries
|
|
72
|
+
# Mollie::SMS.deliveries
|
|
73
|
+
def assert_no_sms_messages
|
|
74
|
+
assert_sms_messages(0) { yield }
|
|
75
|
+
end
|
|
68
76
|
end
|
|
69
77
|
|
|
70
|
-
|
|
71
|
-
|
|
78
|
+
# Extensions and overrides of the Mollie::SMS class for testing purposes.
|
|
79
|
+
#
|
|
80
|
+
# The class method extensions are defined on the
|
|
81
|
+
# {Mollie::SMS::TestHelper::SMSExt::ClassMethods ClassMethods} module.
|
|
82
|
+
module SMSExt
|
|
83
|
+
# @private
|
|
84
|
+
def self.included(klass)
|
|
85
|
+
klass.class_eval do
|
|
86
|
+
undef_method :deliver
|
|
87
|
+
alias_method :deliver, :test_deliver
|
|
88
|
+
extend ClassMethods
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Overrides the normal {Mollie::SMS#deliver deliver} method to *never*
|
|
93
|
+
# make an actual request.
|
|
94
|
+
#
|
|
95
|
+
# Instead, the SMS message, that’s to be delivered, is added to the
|
|
96
|
+
# {Mollie::SMS::TestHelper::SMSExt::ClassMethods#deliveries
|
|
97
|
+
# Mollie::SMS.deliveries} list for later inspection.
|
|
98
|
+
#
|
|
99
|
+
# The parameters are still validated.
|
|
100
|
+
#
|
|
101
|
+
# @return [Response] The stubbed Response instance.
|
|
102
|
+
#
|
|
103
|
+
# @see Mollie::SMS::TestHelper::SMSExt::ClassMethods#stubbed_response
|
|
104
|
+
# Mollie::SMS.stubbed_response
|
|
105
|
+
def deliver
|
|
106
|
+
validate_params!
|
|
107
|
+
self.class.deliveries << self
|
|
108
|
+
self.class.stubbed_response
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
alias_method :test_deliver, :deliver
|
|
112
|
+
|
|
113
|
+
module ClassMethods
|
|
114
|
+
# @return [Array<Mollie::SMS>] A list of sent SMS messages.
|
|
115
|
+
#
|
|
116
|
+
# @see Mollie::SMS::TestHelper::SMSExt#deliver
|
|
117
|
+
# Mollie::SMS#deliver
|
|
118
|
+
def deliveries
|
|
119
|
+
@deliveries ||= []
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Clears the {#deliveries deliveries} list and stubs a {#success!
|
|
123
|
+
# ‘success’} Response instance.
|
|
124
|
+
#
|
|
125
|
+
# @return [Response] The stubbed ‘success’ Response instance.
|
|
126
|
+
def reset!
|
|
127
|
+
@deliveries = []
|
|
128
|
+
success!
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Stubs a ‘success’ Response instance.
|
|
132
|
+
#
|
|
133
|
+
# This means that any following calls to {Mollie::SMS#deliver} will
|
|
134
|
+
# succeed and return the stubbed ‘success’ Response instance.
|
|
135
|
+
#
|
|
136
|
+
# Mollie::SMS.success!
|
|
137
|
+
# response = Mollie::SMS.new(number, body).deliver
|
|
138
|
+
# response.success? # => true
|
|
139
|
+
# response.result_code # => 10
|
|
140
|
+
# response.message # => "Message successfully sent."
|
|
141
|
+
#
|
|
142
|
+
# @return [Response] The stubbed ‘success’ Response instance.
|
|
143
|
+
def success!
|
|
144
|
+
http_response = Net::HTTPOK.new('1.1', '200', 'OK')
|
|
145
|
+
http_response.add_field('Content-type', 'application/xml')
|
|
146
|
+
# @private
|
|
147
|
+
def http_response.read_body; TestHelper::SUCCESS_BODY; end
|
|
148
|
+
@stubbed_response = Mollie::SMS::Response.new(http_response)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Stubs a ‘gateway failure’ Response instance.
|
|
152
|
+
#
|
|
153
|
+
# This means that any following calls to {Mollie::SMS#deliver} will
|
|
154
|
+
# fail at the gateway and return the stubbed ‘gateway failure’
|
|
155
|
+
# Response instance.
|
|
156
|
+
#
|
|
157
|
+
# Mollie::SMS.gateway_failure!
|
|
158
|
+
# response = Mollie::SMS.new(number, body).deliver
|
|
159
|
+
# response.success? # => false
|
|
160
|
+
# response.result_code # => 20
|
|
161
|
+
# response.message # => "No username given."
|
|
162
|
+
#
|
|
163
|
+
# @return [Response] The stubbed ‘gateway failure’ Response
|
|
164
|
+
# instance.
|
|
165
|
+
def gateway_failure!
|
|
166
|
+
http_response = Net::HTTPOK.new('1.1', '200', 'OK')
|
|
167
|
+
http_response.add_field('Content-type', 'application/xml')
|
|
168
|
+
# @private
|
|
169
|
+
def http_response.read_body; TestHelper::FAILURE_BODY; end
|
|
170
|
+
@stubbed_response = Mollie::SMS::Response.new(http_response)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
# Stubs a ‘HTTP failure’ Response instance.
|
|
174
|
+
#
|
|
175
|
+
# This means that any following calls to {Mollie::SMS#deliver} will
|
|
176
|
+
# fail at the HTTP level and return the stubbed ‘HTTP failure’
|
|
177
|
+
# Response instance.
|
|
178
|
+
#
|
|
179
|
+
# Mollie::SMS.http_failure!
|
|
180
|
+
# response = Mollie::SMS.new(number, body).deliver
|
|
181
|
+
# response.success? # => false
|
|
182
|
+
# response.result_code # => 400
|
|
183
|
+
# response.message # => "[HTTP: 400] Bad request"
|
|
184
|
+
#
|
|
185
|
+
# @return [Response] The stubbed ‘HTTP failure’ Response
|
|
186
|
+
# instance.
|
|
187
|
+
def http_failure!
|
|
188
|
+
@stubbed_response = Mollie::SMS::Response.new(Net::HTTPBadRequest.new('1.1', '400', 'Bad request'))
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# @return [Response] The stubbed Response instance that will be
|
|
192
|
+
# returned for all requests from
|
|
193
|
+
# {Mollie::SMS#deliver}.
|
|
194
|
+
def stubbed_response
|
|
195
|
+
@stubbed_response || success!
|
|
196
|
+
end
|
|
197
|
+
end
|
|
72
198
|
end
|
|
73
199
|
end
|
|
74
200
|
end
|
|
75
201
|
end
|
|
76
202
|
|
|
203
|
+
Mollie::SMS.send(:include, Mollie::SMS::TestHelper::SMSExt)
|
data/mollie-sms.gemspec
CHANGED
|
@@ -5,20 +5,20 @@
|
|
|
5
5
|
|
|
6
6
|
Gem::Specification.new do |s|
|
|
7
7
|
s.name = %q{mollie-sms}
|
|
8
|
-
s.version = "0.
|
|
8
|
+
s.version = "1.0.0"
|
|
9
9
|
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
11
|
s.authors = ["Eloy Duran"]
|
|
12
|
-
s.date = %q{2010-08-
|
|
12
|
+
s.date = %q{2010-08-06}
|
|
13
13
|
s.description = %q{Send SMS text messages via the Mollie.nl SMS gateway.}
|
|
14
14
|
s.email = ["eloy@fngtps.com"]
|
|
15
15
|
s.extra_rdoc_files = [
|
|
16
16
|
"LICENSE",
|
|
17
|
-
"README"
|
|
17
|
+
"README.rdoc"
|
|
18
18
|
]
|
|
19
19
|
s.files = [
|
|
20
20
|
"LICENSE",
|
|
21
|
-
"README",
|
|
21
|
+
"README.rdoc",
|
|
22
22
|
"Rakefile",
|
|
23
23
|
"VERSION",
|
|
24
24
|
"lib/mollie/sms.rb",
|
data/rails/init.rb
CHANGED
|
@@ -2,7 +2,7 @@ case Rails.env
|
|
|
2
2
|
when "test"
|
|
3
3
|
require 'mollie/sms/test_helper'
|
|
4
4
|
require 'active_support/test_case'
|
|
5
|
-
ActiveSupport::TestCase.send(:include, Mollie::SMS::TestHelper)
|
|
5
|
+
ActiveSupport::TestCase.send(:include, Mollie::SMS::TestHelper::Assertions)
|
|
6
6
|
when "development"
|
|
7
7
|
require 'mollie/sms/test_helper'
|
|
8
8
|
class Mollie::SMS
|
data/spec/sms_spec.rb
CHANGED
|
@@ -110,7 +110,7 @@ describe "When sending a Mollie::SMS message" do
|
|
|
110
110
|
exception = nil
|
|
111
111
|
begin
|
|
112
112
|
@sms.deliver!
|
|
113
|
-
rescue Mollie::SMS::DeliveryFailure => exception
|
|
113
|
+
rescue Mollie::SMS::Exceptions::DeliveryFailure => exception
|
|
114
114
|
end
|
|
115
115
|
|
|
116
116
|
exception.message.should == "(No username given.) #{@sms.to_s}"
|
|
@@ -210,7 +210,7 @@ describe "Mollie::SMS, concerning validation" do
|
|
|
210
210
|
@sms.params['originator'] = "000000000011112"
|
|
211
211
|
lambda do
|
|
212
212
|
@sms.deliver
|
|
213
|
-
end.should.raise(Mollie::SMS::ValidationError, "Originator may have a maximimun of 14 numerical characters.")
|
|
213
|
+
end.should.raise(Mollie::SMS::Exceptions::ValidationError, "Originator may have a maximimun of 14 numerical characters.")
|
|
214
214
|
end
|
|
215
215
|
|
|
216
216
|
it "accepts an originator of upto 11 alphanumerical characters" do
|
|
@@ -222,6 +222,6 @@ describe "Mollie::SMS, concerning validation" do
|
|
|
222
222
|
@sms.params['originator'] = "0123456789AB"
|
|
223
223
|
lambda do
|
|
224
224
|
@sms.deliver
|
|
225
|
-
end.should.raise(Mollie::SMS::ValidationError, "Originator may have a maximimun of 11 alphanumerical characters.")
|
|
225
|
+
end.should.raise(Mollie::SMS::Exceptions::ValidationError, "Originator may have a maximimun of 11 alphanumerical characters.")
|
|
226
226
|
end
|
|
227
227
|
end
|
data/spec/test_helper_spec.rb
CHANGED
|
@@ -44,8 +44,8 @@ describe "Mollie::SMS ext" do
|
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
describe "Mollie::SMS::TestHelper" do
|
|
48
|
-
extend Mollie::SMS::TestHelper
|
|
47
|
+
describe "Mollie::SMS::TestHelper::Assertions" do
|
|
48
|
+
extend Mollie::SMS::TestHelper::Assertions
|
|
49
49
|
|
|
50
50
|
before do
|
|
51
51
|
Mollie::SMS.reset!
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mollie-sms
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
hash:
|
|
4
|
+
hash: 23
|
|
5
5
|
prerelease: false
|
|
6
6
|
segments:
|
|
7
|
-
- 0
|
|
8
|
-
- 2
|
|
9
7
|
- 1
|
|
10
|
-
|
|
8
|
+
- 0
|
|
9
|
+
- 0
|
|
10
|
+
version: 1.0.0
|
|
11
11
|
platform: ruby
|
|
12
12
|
authors:
|
|
13
13
|
- Eloy Duran
|
|
@@ -15,7 +15,7 @@ autorequire:
|
|
|
15
15
|
bindir: bin
|
|
16
16
|
cert_chain: []
|
|
17
17
|
|
|
18
|
-
date: 2010-08-
|
|
18
|
+
date: 2010-08-06 00:00:00 +02:00
|
|
19
19
|
default_executable:
|
|
20
20
|
dependencies:
|
|
21
21
|
- !ruby/object:Gem::Dependency
|
|
@@ -43,10 +43,10 @@ extensions: []
|
|
|
43
43
|
|
|
44
44
|
extra_rdoc_files:
|
|
45
45
|
- LICENSE
|
|
46
|
-
- README
|
|
46
|
+
- README.rdoc
|
|
47
47
|
files:
|
|
48
48
|
- LICENSE
|
|
49
|
-
- README
|
|
49
|
+
- README.rdoc
|
|
50
50
|
- Rakefile
|
|
51
51
|
- VERSION
|
|
52
52
|
- lib/mollie/sms.rb
|
data/README
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
A Ruby client that allows you to send SMS messages via http://mollie.nl.
|
|
2
|
-
|
|
3
|
-
It does only what we need, for our app, at this point in time. Which means that
|
|
4
|
-
connects to the webservice via SSL, and only sends a message to one recipient
|
|
5
|
-
at a time.
|
|
6
|
-
|
|
7
|
-
Patches are accepted.
|