activesms 0.0.2 → 0.6.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/CHANGELOG +3 -0
- data/MIT-LICENSE +20 -0
- data/Manifest.txt +19 -0
- data/generators/sms/USAGE +19 -0
- data/generators/sms/sms_generator.rb +31 -0
- data/generators/sms/templates/fixture.rhtml +1 -0
- data/generators/sms/templates/model.rb +11 -0
- data/generators/sms/templates/unit_test.rb +31 -0
- data/init.rb +2 -0
- data/lib/activesms/adv_attr_accessor.rb +32 -0
- data/lib/activesms/base.rb +217 -0
- data/lib/activesms/connection_adapters/abstract_adapter.rb +52 -0
- data/lib/activesms/connection_adapters/bulk_sms_adapter.rb +67 -0
- data/lib/activesms/connection_adapters/clickatell_adapter.rb +51 -0
- data/lib/activesms/connection_adapters/simplewire_adapter.rb +58 -0
- data/lib/activesms/connections.rb +64 -0
- data/lib/activesms/exceptions.rb +23 -0
- data/lib/activesms/sms.rb +11 -0
- data/lib/activesms/validations.rb +49 -0
- data/lib/activesms/version.rb +2 -2
- data/website/index.html +40 -16
- data/website/index.txt +27 -11
- data/website/template.rhtml +1 -4
- metadata +20 -1
data/CHANGELOG
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2007 Robert Cottrell
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOa AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SaALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest.txt
CHANGED
@@ -1,12 +1,31 @@
|
|
1
|
+
CHANGELOG
|
1
2
|
History.txt
|
2
3
|
License.txt
|
4
|
+
MIT-LICENSE
|
3
5
|
Manifest.txt
|
4
6
|
README.txt
|
5
7
|
Rakefile
|
8
|
+
generators/sms/USAGE
|
9
|
+
generators/sms/sms_generator.rb
|
10
|
+
generators/sms/templates/fixture.rhtml
|
11
|
+
generators/sms/templates/model.rb
|
12
|
+
generators/sms/templates/unit_test.rb
|
13
|
+
init.rb
|
6
14
|
lib/activesms.rb
|
15
|
+
lib/activesms/adv_attr_accessor.rb
|
16
|
+
lib/activesms/base.rb
|
17
|
+
lib/activesms/connection_adapters/abstract_adapter.rb
|
18
|
+
lib/activesms/connection_adapters/bulk_sms_adapter.rb
|
19
|
+
lib/activesms/connection_adapters/clickatell_adapter.rb
|
20
|
+
lib/activesms/connection_adapters/simplewire_adapter.rb
|
21
|
+
lib/activesms/connections.rb
|
22
|
+
lib/activesms/exceptions.rb
|
23
|
+
lib/activesms/sms.rb
|
24
|
+
lib/activesms/validations.rb
|
7
25
|
lib/activesms/version.rb
|
8
26
|
scripts/txt2html
|
9
27
|
setup.rb
|
28
|
+
test/connection_adapters/test_simplewire_adapter.rb
|
10
29
|
test/test_activesms.rb
|
11
30
|
test/test_helper.rb
|
12
31
|
website/index.html
|
@@ -0,0 +1,19 @@
|
|
1
|
+
Active SMS Generator
|
2
|
+
|
3
|
+
Description:
|
4
|
+
The SMS generator creates stubs for a new SMS model.
|
5
|
+
|
6
|
+
The generator takes an SMS model name and a list of SMS methods as
|
7
|
+
arguments. The model name may be given in CamelCase or under_score.
|
8
|
+
|
9
|
+
The generator creates an SMS model class in app/models and a test suite
|
10
|
+
with fixtures in test/unit.
|
11
|
+
|
12
|
+
Example:
|
13
|
+
./script/generate sms Notifier signup forgot_password
|
14
|
+
|
15
|
+
This will create a Nofier SMS class:
|
16
|
+
Model: app/models/notifier.rb
|
17
|
+
Test: test/unit/notifier_test.rb
|
18
|
+
Fixtures: test/fixtures/notifier/signup
|
19
|
+
test/fixtures/notifier/forgot_password
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class SmsGenerator < Rails::Generator::NamedBase
|
2
|
+
def manifest
|
3
|
+
record do |m|
|
4
|
+
# Check for class naming collisions.
|
5
|
+
m.class_collisions class_path, class_name, "#{class_name}Test"
|
6
|
+
|
7
|
+
# Create model, view, test, and fixture directories.
|
8
|
+
m.directory File.join('app/models', class_path)
|
9
|
+
m.directory File.join('test/unit', class_path)
|
10
|
+
m.directory File.join('test/fixtures', file_path)
|
11
|
+
|
12
|
+
# Create model class and unit test.
|
13
|
+
m.template "model.rb", File.join('app/models',
|
14
|
+
class_path,
|
15
|
+
"#{file_name}.rb")
|
16
|
+
m.template "unit_test.rb", File.join('test/unit',
|
17
|
+
class_path,
|
18
|
+
"#{file_name}_test.rb")
|
19
|
+
|
20
|
+
# Create fixture for each action.
|
21
|
+
actions.each do |action|
|
22
|
+
relative_path = File.join(file_path, action)
|
23
|
+
fixture_path = File.join('test/fixtures', relative_path)
|
24
|
+
|
25
|
+
m.template "fixture.rhtml", fixture_path,
|
26
|
+
:assigns => { :action => action, :path => fixture_path }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= class_name %>#<%= action %>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../test_helper'
|
2
|
+
|
3
|
+
class <%= class_name %>Test < Test::Unit::TestCase
|
4
|
+
FIXTURES_PATH = File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../fixtures'
|
5
|
+
|
6
|
+
def setup
|
7
|
+
ActiveSms::Base.delivery_method = :test
|
8
|
+
ActiveSms::Base.perform_deliveries = true
|
9
|
+
ActiveSms::Base.deliveries = []
|
10
|
+
|
11
|
+
@expected = ActiveSms::Sms.new
|
12
|
+
end
|
13
|
+
|
14
|
+
<% actions.each do |action| -%>
|
15
|
+
def test_<%= action %>
|
16
|
+
@expected.recipients = ''
|
17
|
+
@expected.from = ''
|
18
|
+
@expected.body = read_fixture('<%= action %>')
|
19
|
+
|
20
|
+
actual = <%= class_name %>.create_<%= action %>
|
21
|
+
assert_equal @expected.recipients, actual.recipients
|
22
|
+
assert_equal @expected.from, actual.from
|
23
|
+
assert_equal @expected.body, actual.body
|
24
|
+
end
|
25
|
+
|
26
|
+
<% end -%>
|
27
|
+
private
|
28
|
+
def read_fixture(action)
|
29
|
+
IO.read("#{FIXTURES_PATH}/<%= file_path %>/#{action}")
|
30
|
+
end
|
31
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module ActiveSms
|
2
|
+
module AdvAttrAccessor #:nodoc:
|
3
|
+
def self.included(base)
|
4
|
+
base.extend(ClassMethods)
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods #:nodoc:
|
8
|
+
def adv_attr_accessor(*names)
|
9
|
+
names.each do |name|
|
10
|
+
ivar = "@#{name}"
|
11
|
+
|
12
|
+
define_method("#{name}=") do |value|
|
13
|
+
instance_variable_set(ivar, value)
|
14
|
+
end
|
15
|
+
|
16
|
+
define_method(name) do |*parameters|
|
17
|
+
if parameters.length > 1
|
18
|
+
raise ArgumentError, "expected 0 or 1 parameters"
|
19
|
+
end
|
20
|
+
if parameters.empty?
|
21
|
+
if instance_variables.include?(ivar)
|
22
|
+
instance_variable_get(ivar)
|
23
|
+
end
|
24
|
+
else
|
25
|
+
instance_variable_set(ivar, parameters.first)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,217 @@
|
|
1
|
+
require 'activesms/adv_attr_accessor'
|
2
|
+
require 'activesms/sms'
|
3
|
+
require 'net/https'
|
4
|
+
|
5
|
+
module ActiveSms #:nodoc:
|
6
|
+
|
7
|
+
# Active SMS allows you to send SMS messages from your application using
|
8
|
+
# an SMS model.
|
9
|
+
#
|
10
|
+
# = SMS models
|
11
|
+
#
|
12
|
+
# To use Action SMS, you need to create an SMS model.
|
13
|
+
#
|
14
|
+
# $ script/generate sms Notifier signup
|
15
|
+
#
|
16
|
+
# The generated model inherits from ActiveSms::Base. SMS messages are
|
17
|
+
# defined by creating methods on the model which are then used to set
|
18
|
+
# variables to be used in the message or to change options on the message.
|
19
|
+
#
|
20
|
+
# Examples:
|
21
|
+
#
|
22
|
+
# class Notifier < ActiveSms::Base
|
23
|
+
# def signup
|
24
|
+
# recipients "447987654321"
|
25
|
+
# from "447123456789"
|
26
|
+
# body "Your account has been created"
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# Sender methods have the following configuration methods available.
|
31
|
+
#
|
32
|
+
# * <tt>recipients</tt> - Takes one or more destination numbers. These
|
33
|
+
# numbers should be formatted in standard international number format.
|
34
|
+
#
|
35
|
+
# * <tt>from</tt> - Who the SMS message you are sending is from. This
|
36
|
+
# may be either a number formatted in standard internation number format,
|
37
|
+
# or, if the gateway supports it, an alphanumeric origination.
|
38
|
+
#
|
39
|
+
# * <tt>body</tt> - The content of the message. This must fit within the
|
40
|
+
# length limitation of SMS messages.
|
41
|
+
#
|
42
|
+
# = Sending SMS messages
|
43
|
+
#
|
44
|
+
# Once an SMS action is defined, you can deliver you message or create it
|
45
|
+
# and save it for delivery later.
|
46
|
+
#
|
47
|
+
# Notifier.deliver_signup_noification(david) # sends the SMS message
|
48
|
+
#
|
49
|
+
# sms = Notifier.create_signup_notification(david) # an SMS object
|
50
|
+
# Notifier.deliver(sms)
|
51
|
+
#
|
52
|
+
# You never instantiate your model class. Rather, your delivery instance
|
53
|
+
# methods are automatically wrapped in class methods that start with the
|
54
|
+
# word <tt>deliver</tt> followed by the name of the SMS method that you
|
55
|
+
# would like to deliver. The <tt>signup_notification</tt> method defined
|
56
|
+
# above is delivered by invoking <tt>Notifier.deliver_signup_notification</tt>.
|
57
|
+
#
|
58
|
+
# = Configuration options
|
59
|
+
#
|
60
|
+
# These options are specified on the class level.
|
61
|
+
#
|
62
|
+
# * <tt>logger</tt> - The logger is used for generating information about
|
63
|
+
# the sending run if available. This can be set to nil for no logging.
|
64
|
+
# It is compatible with Ruby's own Logger and Log4r loggers.
|
65
|
+
#
|
66
|
+
# * <tt>gateway_settings</tt> - Allows detailed configuration of the SMS
|
67
|
+
# gateway used to deliver the messages. Some gateways may require
|
68
|
+
# additional configuration settings.
|
69
|
+
#
|
70
|
+
# * <tt>raise_delivery_errors</tt> - Determines whether or not errors should
|
71
|
+
# be raised if the SMS fails to be delivered.
|
72
|
+
#
|
73
|
+
# * <tt>delivery_method</tt> - Defines a delivery method. Possible values
|
74
|
+
# are :gateway (default) or :test.
|
75
|
+
#
|
76
|
+
# * <tt>perform_deliveries</tt> - Determines whether or not deliver_*
|
77
|
+
# methods are actually carried out. By default they are, but this can be
|
78
|
+
# turned off to help functional testing.
|
79
|
+
#
|
80
|
+
# * <tt>deliveries</tt> - Keeps an array of all the messages sent out through
|
81
|
+
# Active SMS with deliver_method :test. Most useful for unit and functional
|
82
|
+
# testing.
|
83
|
+
class Base
|
84
|
+
include AdvAttrAccessor
|
85
|
+
include ActionController::UrlWriter
|
86
|
+
|
87
|
+
@@logger = nil
|
88
|
+
cattr_accessor :logger
|
89
|
+
|
90
|
+
private_class_method :new #:nodoc:
|
91
|
+
|
92
|
+
@@raise_delivery_errors = true
|
93
|
+
cattr_accessor :raise_delivery_errors
|
94
|
+
|
95
|
+
@@delivery_method = :gateway
|
96
|
+
cattr_accessor :delivery_method
|
97
|
+
|
98
|
+
@@perform_deliveries = true
|
99
|
+
cattr_accessor :perform_deliveries
|
100
|
+
|
101
|
+
@@deliveries = []
|
102
|
+
cattr_accessor :deliveries
|
103
|
+
|
104
|
+
# The recipient numbers for the message, either as a string (for a single
|
105
|
+
# recipient) or an array (for multiple recipients).
|
106
|
+
adv_attr_accessor :recipients
|
107
|
+
|
108
|
+
# Specify the from number or identifier for the message.
|
109
|
+
adv_attr_accessor :from
|
110
|
+
|
111
|
+
# Specify the subject of the message.
|
112
|
+
adv_attr_accessor :subject
|
113
|
+
|
114
|
+
# The content of the message.
|
115
|
+
adv_attr_accessor :body
|
116
|
+
|
117
|
+
# The Sms message object instance referenced by this model.
|
118
|
+
attr_reader :sms
|
119
|
+
|
120
|
+
class << self
|
121
|
+
def method_missing(method_symbol, *parameters) #:nodoc:
|
122
|
+
case method_symbol.id2name
|
123
|
+
when /^create_([_a-z]\w+)/ then new($1, *parameters).sms
|
124
|
+
when /^deliver_([_a-z]\w+)/ then new($1, *parameters).deliver!
|
125
|
+
when "new" then nil
|
126
|
+
else super
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Receives an SMS message, parses it into an SMS object, instantiates
|
131
|
+
# a new model, and passes the message object to the model object's
|
132
|
+
# #receive method. If you want your model to be able to process
|
133
|
+
# incoming messages, you'll need to implement a #receive method
|
134
|
+
# that accepts the SMS object as a parameter.
|
135
|
+
#
|
136
|
+
# class Notifier < ActionSms::Base
|
137
|
+
# def receive(sms)
|
138
|
+
# ...
|
139
|
+
# end
|
140
|
+
# end
|
141
|
+
def receive(sms)
|
142
|
+
sms = connection.parse(sms)
|
143
|
+
new.receive(sms)
|
144
|
+
end
|
145
|
+
|
146
|
+
# Deliver the given Sms message object directly. This can be used to
|
147
|
+
# deliver a preconstructed message, like:
|
148
|
+
#
|
149
|
+
# sms = Notifier.create_signup_notification(parameters)
|
150
|
+
# Notifier.deliver(sms)
|
151
|
+
def deliver(sms)
|
152
|
+
new.deliver!(sms)
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
# Instantiate a new Active SMS model object. If +method_name+ is not
|
158
|
+
# +nil+, the model will be initialized according to the named method.
|
159
|
+
# If not, the model will remain uninitialized (useful when you need to
|
160
|
+
# invoke the "receive" method, for instance).
|
161
|
+
def initialize(method_name = nil, *parameters) #:nodoc:
|
162
|
+
create!(method_name, *parameters) if method_name
|
163
|
+
end
|
164
|
+
|
165
|
+
# Initialize the model via the given +method_name+. The body will be
|
166
|
+
# rendered and a new Sms object created.
|
167
|
+
def create!(method_name, *parameters) #:nodoc:
|
168
|
+
initialize_defaults(method_name)
|
169
|
+
send(method_name, *parameters)
|
170
|
+
|
171
|
+
# Build the SMS object itself.
|
172
|
+
@sms = create_sms
|
173
|
+
end
|
174
|
+
|
175
|
+
# Delivers an Sms message object. By default, it deliver the cached object
|
176
|
+
# (from the #create! method). If no cached object exists, and no
|
177
|
+
# alternate has been give as the prameter, this will fail.
|
178
|
+
def deliver!(sms = @sms) #:nodoc:
|
179
|
+
raise "no SMS object available for delivery!" unless sms
|
180
|
+
logger.info "Sending SMS: #{sms}" unless logger.nil?
|
181
|
+
|
182
|
+
begin
|
183
|
+
send("perform_delivery_#{delivery_method}", sms) if perform_deliveries
|
184
|
+
rescue Exception => e
|
185
|
+
raise e if raise_delivery_errors
|
186
|
+
end
|
187
|
+
|
188
|
+
return sms
|
189
|
+
end
|
190
|
+
|
191
|
+
private
|
192
|
+
|
193
|
+
# Set up the default values for the various instance variables of this
|
194
|
+
# model. Subclasses may override this method to provide different
|
195
|
+
# defaults.
|
196
|
+
def initialize_defaults(method_name)
|
197
|
+
end
|
198
|
+
|
199
|
+
def create_sms
|
200
|
+
sms = Sms.new
|
201
|
+
sms.recipients = recipients
|
202
|
+
sms.from = from
|
203
|
+
sms.body = body
|
204
|
+
@sms = sms
|
205
|
+
end
|
206
|
+
|
207
|
+
def perform_delivery_gateway(sms)
|
208
|
+
raise ConnectionNotEstablished unless connection
|
209
|
+
connection.deliver(sms)
|
210
|
+
end
|
211
|
+
|
212
|
+
def perform_delivery_test(sms)
|
213
|
+
deliveries << sms
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
|
3
|
+
module ActiveSms #:nodoc:
|
4
|
+
module ConnectionAdapters #:nodoc:
|
5
|
+
# All the concrete gateway adapters follow the interface laid down in this
|
6
|
+
# class. You can use this interface directly by borrowing the gateway
|
7
|
+
# connection from the Base with Base.connection.
|
8
|
+
class AbstractAdapter
|
9
|
+
|
10
|
+
@logger = nil
|
11
|
+
attr_accessor :logger
|
12
|
+
|
13
|
+
def initialize(logger = nil) #:nodoc:
|
14
|
+
@logger = logger
|
15
|
+
end
|
16
|
+
|
17
|
+
# Return the human readable name of the gateway adapter.
|
18
|
+
def adapter_name
|
19
|
+
return 'Abstract'
|
20
|
+
end
|
21
|
+
|
22
|
+
def deliver(sms)
|
23
|
+
end
|
24
|
+
|
25
|
+
def parse(sms)
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
# Helper method to send an HTTP request to +url+ with paramaters
|
32
|
+
# specified by the +params+ hash.
|
33
|
+
def send_http_request(url, params)
|
34
|
+
uri = URI.parse(url)
|
35
|
+
req = Net::HTTP::Post.new(uri.path)
|
36
|
+
req.set_form_data(params)
|
37
|
+
|
38
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
39
|
+
http.use_ssl = true if uri.scheme == 'https'
|
40
|
+
resp = http.start do
|
41
|
+
http.request(req)
|
42
|
+
end
|
43
|
+
@logger.info "Response: #{resp.body}" unless @logger.nil?
|
44
|
+
|
45
|
+
return resp.body
|
46
|
+
rescue Exception => e
|
47
|
+
raise e
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'activesms/connection_adapters/abstract_adapter'
|
2
|
+
|
3
|
+
module ActiveSms
|
4
|
+
class Base
|
5
|
+
def self.bulk_sms_connection(config) #:nodoc:
|
6
|
+
return ConnectionAdapters::BulkSmsAdapter.new(logger, config)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module ConnectionAdapters
|
11
|
+
class BulkSmsAdapter < AbstractAdapter
|
12
|
+
|
13
|
+
SERVICE_HOSTS = {
|
14
|
+
:international => 'bulksms.vsms.net',
|
15
|
+
:safrica => 'bulksms.2way.co.za',
|
16
|
+
:spoin => 'bulksms.com.es',
|
17
|
+
:uk => 'www.bulksms.co.uk',
|
18
|
+
:usa => 'usa.bulksms.com'
|
19
|
+
}
|
20
|
+
SERVICE_PORT = 5567
|
21
|
+
SERVICE_PATH = '/eapi/submission/send_sms/2/2.0'
|
22
|
+
|
23
|
+
STATUS_MESSAGES = {
|
24
|
+
0 => 'in progress',
|
25
|
+
1 => 'scheduled',
|
26
|
+
22 => 'internal fatal error',
|
27
|
+
23 => 'authentication failure',
|
28
|
+
24 => 'data validation failed',
|
29
|
+
25 => 'insufficient credits',
|
30
|
+
26 => 'upstream credits not available',
|
31
|
+
27 => 'daily quota exceeded',
|
32
|
+
28 => 'upstream quota exceeded',
|
33
|
+
40 => 'temporarily unavailable'
|
34
|
+
}
|
35
|
+
|
36
|
+
# Create an adapter for the BulkSMS gateway.
|
37
|
+
#
|
38
|
+
# Options:
|
39
|
+
# * <tt>:region</tt>
|
40
|
+
# * <tt>:username</tt>
|
41
|
+
# * <tt>:password</tt>
|
42
|
+
def initialize(logger = nil, config = {})
|
43
|
+
super(logger)
|
44
|
+
@config = config.dup
|
45
|
+
|
46
|
+
host = SERVICE_HOSTS[config[:region]] || SERVICE_HOSTS[:uk]
|
47
|
+
@service_url = "http://#{host}:#{SERVICE_PORT}#{SERVICE_PATH}"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Return the human readable name of the connection adapter name.
|
51
|
+
def adpter_name
|
52
|
+
return 'BulkSMS'
|
53
|
+
end
|
54
|
+
|
55
|
+
def deliver(sms)
|
56
|
+
params = {
|
57
|
+
:username => @config[:username],
|
58
|
+
:password => @config[:password],
|
59
|
+
:msisdn => sms.recipients,
|
60
|
+
:message => sms.body,
|
61
|
+
}
|
62
|
+
send_http_request(@service_url, params)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'activesms/connection_adapters/abstract_adapter'
|
2
|
+
|
3
|
+
module ActiveSms
|
4
|
+
class Base
|
5
|
+
def self.clickatell_connection(config) #:nodoc:
|
6
|
+
return ConnectionAdapters::ClickatellAdapter.new(logger, config)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module ConnectionAdapters
|
11
|
+
class ClickatellAdapter < AbstractAdapter
|
12
|
+
|
13
|
+
SERVICE_HOST = "api.clickatell.com"
|
14
|
+
SERVICE_PATH = "/http/sendmsg"
|
15
|
+
|
16
|
+
# Create an adapter for the Clickatell gateway.
|
17
|
+
#
|
18
|
+
# Options:
|
19
|
+
#
|
20
|
+
# * <tt>:user</tt>
|
21
|
+
# * <tt>:password</tt>
|
22
|
+
# * <tt>:api_id</tt>
|
23
|
+
# * <tt>use_ssl</tt>
|
24
|
+
def initialize(logger = nil, config = {})
|
25
|
+
super(logger)
|
26
|
+
@config = config.dup
|
27
|
+
|
28
|
+
scheme = config[:use_ssl] ? "https" : "http"
|
29
|
+
@service_url = "#{scheme}://#{SERVICE_HOST}#{SERVICE_PATH}"
|
30
|
+
end
|
31
|
+
|
32
|
+
# Return the human readable name of the gateway adapter name.
|
33
|
+
def adpter_name
|
34
|
+
return 'Clickatell'
|
35
|
+
end
|
36
|
+
|
37
|
+
def deliver(sms)
|
38
|
+
params = {
|
39
|
+
:user => @config[:user],
|
40
|
+
:password => @config[:password],
|
41
|
+
:api_id => @config[:api_id],
|
42
|
+
:to => sms.recipients,
|
43
|
+
:from => sms.from,
|
44
|
+
:text => sms.body
|
45
|
+
}
|
46
|
+
send_http_request(@service_url, params)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'activesms/connection_adapters/abstract_adapter'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'java'
|
5
|
+
include_class 'com.simplewire.sms.SMS'
|
6
|
+
rescue LoadError
|
7
|
+
puts "JRuby is required for the simplewire adapter"
|
8
|
+
raise $!
|
9
|
+
end
|
10
|
+
|
11
|
+
module ActiveSms
|
12
|
+
class Base
|
13
|
+
def self.simplewire_connection(config) #:nodoc:
|
14
|
+
return ConnectionAdapters::SimplewireAdapter.new(logger, config)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module ConnectionAdapters
|
19
|
+
class SimplewireAdapter < AbstractAdapter
|
20
|
+
|
21
|
+
# Create a simplewire adapter. The config requires subscriber_id and subscriber_password.
|
22
|
+
def initialize(logger = nil, config = {})
|
23
|
+
super(logger)
|
24
|
+
@config = config.dup
|
25
|
+
@config.symbolize_keys!
|
26
|
+
|
27
|
+
unless @config.member?(:subscriber_id)
|
28
|
+
raise "subscriber_id is required for simplewire"
|
29
|
+
end
|
30
|
+
unless @config.member?(:subscriber_password)
|
31
|
+
raise "subscriber_password is required for simplewire"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Return the human readable name of the gateway adapter name.
|
36
|
+
def adpter_name
|
37
|
+
return 'Simplewire'
|
38
|
+
end
|
39
|
+
|
40
|
+
# Send the sms message using the simplewire adapter
|
41
|
+
def deliver(sms)
|
42
|
+
create_sms(sms).submit()
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse(sms)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Create the simplewire sms message to send
|
49
|
+
def create_sms(sms)
|
50
|
+
s = SMS.new
|
51
|
+
s.destination_addr = sms.recipients
|
52
|
+
s.source_addr = sms.from
|
53
|
+
s.msg_text = sms.body
|
54
|
+
s
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module ActiveSms #:nodoc#
|
2
|
+
|
3
|
+
class Base
|
4
|
+
@@connection = nil
|
5
|
+
|
6
|
+
class << self
|
7
|
+
# Returns true if a connection that's accessible to this class has already
|
8
|
+
# been opened.
|
9
|
+
def connected?
|
10
|
+
return !@@connection.nil?
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns the connection currently associated with the class. This can
|
14
|
+
# also be used to "borrow" the connection to do work that is specific to
|
15
|
+
# a particular SMS gateway.
|
16
|
+
def connection
|
17
|
+
raise ConnectionNotEstablished unless @@connection
|
18
|
+
return @@connection
|
19
|
+
end
|
20
|
+
|
21
|
+
# Set the gateway connection for the class.
|
22
|
+
def connection=(spec) #:nodoc:
|
23
|
+
raise ConnectionNotEstablished unless spec
|
24
|
+
@@connection = spec
|
25
|
+
end
|
26
|
+
|
27
|
+
# Establishes the connection to the SMS gateway. Accepts a hash as input
|
28
|
+
# where the :adapter key must be specified with the name of a gateway
|
29
|
+
# adapter (in lower-case)
|
30
|
+
#
|
31
|
+
# ActiveSms::Base.establish_connection(
|
32
|
+
# :adapter => "clickatell",
|
33
|
+
# :username => "myusername",
|
34
|
+
# :password => "mypassword"
|
35
|
+
# :api_id => "myapiid"
|
36
|
+
# )
|
37
|
+
#
|
38
|
+
# Also accepts keys as strings (for parsing from YAML, for example).
|
39
|
+
#
|
40
|
+
# The exceptions AdapterNotSpecified, AdapterNotFound, and ArgumentError
|
41
|
+
# may be returned.
|
42
|
+
def establish_connection(config)
|
43
|
+
config = config.symbolize_keys
|
44
|
+
unless config.key?(:adapter)
|
45
|
+
raise AdapterNotSpecified, "#{config} adapter is not configured"
|
46
|
+
end
|
47
|
+
adapter_method = "#{config[:adapter]}_connection"
|
48
|
+
unless respond_to?(adapter_method)
|
49
|
+
raise AdapterNotFound,
|
50
|
+
"configuration specifies nonexistent #{config[:adapter]} adapter"
|
51
|
+
end
|
52
|
+
self.connection = self.send(adapter_method, config)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns the connection currently associated with the class. This can
|
57
|
+
# also be used to "borrow" the connection to do work that is specific to
|
58
|
+
# a particular SMS gateway.
|
59
|
+
def connection
|
60
|
+
self.class.connection
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ActiveSms #:nodoc:
|
2
|
+
|
3
|
+
# Generic error class and superclass of all other errors raised by
|
4
|
+
# Active SMS
|
5
|
+
class ActiveSmsError < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
# The configuration hash used in <tt>establish_connection</tt> didn't include
|
9
|
+
# <tt>:adapter</tt> key
|
10
|
+
class AdapterNotSpecified < ActiveSmsError
|
11
|
+
end
|
12
|
+
|
13
|
+
# The <tt>adapter</tt> key used in <tt>establish_connection</tt> specified a
|
14
|
+
# nonexistent adapter.
|
15
|
+
class AdapterNotFound < ActiveSmsError
|
16
|
+
end
|
17
|
+
|
18
|
+
# No connection has been established. Use <tt>establish_connection</tt>
|
19
|
+
# before sending a message.
|
20
|
+
class ConnectionNotEstablished < ActiveSmsError
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module ActiveSms
|
2
|
+
# The SMS message object is invalid. Use the sms method to retrieve the
|
3
|
+
# message which did not validate.
|
4
|
+
class SmsInvalid < ActiveSmsError
|
5
|
+
attr_reader :sms
|
6
|
+
def initialize(sms)
|
7
|
+
@sms = sms
|
8
|
+
super("Validation failed: #{@sms.errors.full_messages.join(', ')}")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Active SMS validation is reported to and from this object, which is used
|
13
|
+
# by Base to determine whether the message is in a valid state to be sent.
|
14
|
+
class Errors
|
15
|
+
include Enumerable
|
16
|
+
|
17
|
+
# Holds a hash with all the default error message. This can be replaced
|
18
|
+
# by your own copy or localizations.
|
19
|
+
@@default_error_messages = {
|
20
|
+
:invalid => "is invalid"
|
21
|
+
}
|
22
|
+
cattr_accessor :default_error_messages
|
23
|
+
|
24
|
+
def initialize(base) #:nodoc:
|
25
|
+
@base = base
|
26
|
+
@errors = {}
|
27
|
+
end
|
28
|
+
|
29
|
+
# Adds an error message to the base object instead of any particular
|
30
|
+
# attribute for the object. This is used to report errors that don't
|
31
|
+
# tie to any specific attribute, but to the object as a whole. These
|
32
|
+
# error messages don't get prepended with any field name when iterating
|
33
|
+
# with each_full, so they should be complete sentences.
|
34
|
+
def add_to_base(msg)
|
35
|
+
add(:base, msg)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Adds an error message +msg+ to the +attribute+, which will be returned
|
39
|
+
# on a call to <tt>on(attribute)</tt> for the same attribute and ensure
|
40
|
+
# that this error object returns false when asked if <tt>empty?</tt>.
|
41
|
+
# More than one error can be added to the same +attribute+, in which
|
42
|
+
# case an array will be returned on a call to <tt>on(attribute)</tt>.
|
43
|
+
# If no +msg+ is supplied, "invalid" is assumed.
|
44
|
+
def add(attribute, msg = @@default_error_messages[:invalid])
|
45
|
+
@errors[attribute.to_s] ||= []
|
46
|
+
@errors[attribute.to_s] << msg
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/activesms/version.rb
CHANGED
data/website/index.html
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
<link rel="stylesheet" href="stylesheets/screen.css" type="text/css" media="screen" />
|
6
6
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
7
7
|
<title>
|
8
|
-
|
8
|
+
ActiveSms
|
9
9
|
</title>
|
10
10
|
<script src="javascripts/rounded_corners_lite.inc.js" type="text/javascript"></script>
|
11
11
|
<style>
|
@@ -30,7 +30,7 @@
|
|
30
30
|
<body>
|
31
31
|
<div id="main">
|
32
32
|
|
33
|
-
<h1>
|
33
|
+
<h1>ActiveSms</h1>
|
34
34
|
<div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/activesms"; return false'>
|
35
35
|
<p>Get Version</p>
|
36
36
|
<a href="http://rubyforge.org/projects/activesms" class="numbers">0.0.2</a>
|
@@ -38,33 +38,60 @@
|
|
38
38
|
<h2>What</h2>
|
39
39
|
|
40
40
|
|
41
|
+
<p>Active <span class="caps">SMS</span> is a framework for creating and sending <span class="caps">SMS</span> messages.</p>
|
42
|
+
|
43
|
+
|
41
44
|
<h2>Installing</h2>
|
42
45
|
|
43
46
|
|
44
47
|
<pre syntax="ruby">sudo gem install activesms</pre>
|
45
48
|
|
46
|
-
<h2>
|
49
|
+
<h2>Demonstration of usage</h2>
|
47
50
|
|
48
51
|
|
49
|
-
<
|
52
|
+
<p><span class="caps">TBD</span>.</p>
|
50
53
|
|
51
54
|
|
52
|
-
<h2>
|
55
|
+
<h2>Supported Gateways</h2>
|
56
|
+
|
57
|
+
|
58
|
+
<p>Active <span class="caps">SMS</span> will require a valid account from a third party <span class="caps">SMS</span> gateway to
|
59
|
+
send or receive <span class="caps">SMS</span> messages. The following gateways are currently supported:</p>
|
53
60
|
|
54
61
|
|
55
|
-
<
|
62
|
+
<ul>
|
63
|
+
<li>BulkSMS[http://www.bulksms.com]</li>
|
64
|
+
<li>Clickatell[http://www.clickatell.com]</li>
|
65
|
+
<li>Simplewire[http://www.simplewire.com] (requires jruby)</li>
|
66
|
+
</ul>
|
56
67
|
|
57
68
|
|
58
|
-
<p
|
69
|
+
<p>Not all features are supported by all gateways.</p>
|
59
70
|
|
60
71
|
|
61
|
-
<
|
72
|
+
<h3>Simplewire Configuration</h3>
|
62
73
|
|
63
74
|
|
64
|
-
<
|
75
|
+
<ul>
|
76
|
+
<li>Make sure you are using jruby</li>
|
77
|
+
<li>Make sure swsms.jar is in your classpath (Download at: <a href="http://www.simplewire.com/developers/sdk/java/">http://www.simplewire.com/developers/sdk/java/</a>)</li>
|
78
|
+
<li>Add the following configuration code to the rails environment.</li>
|
79
|
+
</ul>
|
65
80
|
|
66
81
|
|
67
|
-
|
82
|
+
<pre syntax="ruby">
|
83
|
+
ActiveSms::Base.establish_connection(
|
84
|
+
:adapter => "simplewire",
|
85
|
+
:subscriber_id => "id",
|
86
|
+
:subscriber_password => "password"
|
87
|
+
)
|
88
|
+
|
89
|
+
</pre>
|
90
|
+
|
91
|
+
<h2>Forum</h2>
|
92
|
+
|
93
|
+
|
94
|
+
<p><a href="http://rubyforge.org/forum/?group_id=2923">http://rubyforge.org/forum/?group_id=2923</a></p>
|
68
95
|
|
69
96
|
|
70
97
|
<h2>License</h2>
|
@@ -73,14 +100,11 @@
|
|
73
100
|
<p>This code is free to use under the terms of the <span class="caps">MIT</span> license.</p>
|
74
101
|
|
75
102
|
|
76
|
-
<h2>
|
103
|
+
<h2>Support</h2>
|
104
|
+
|
77
105
|
|
106
|
+
<p>You can find the Active <span class="caps">SMS</span> RubyForge page at <a href="http://rubyforge.org/projects/activesms">http://rubyforge.org/projects/activesms</a>.</p>
|
78
107
|
|
79
|
-
<p>Comments are welcome. Send an email to <a href="mailto:FIXME"><span class="caps">FIXME</span> full name</a> email.</p>
|
80
|
-
<p class="coda">
|
81
|
-
<a href="mailto:drnicwilliams@gmail.com">Dr Nic</a>, 26th July 2007<br>
|
82
|
-
Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
|
83
|
-
</p>
|
84
108
|
</div>
|
85
109
|
|
86
110
|
<!-- insert site tracking codes here, like Google Urchin -->
|
data/website/index.txt
CHANGED
@@ -1,35 +1,51 @@
|
|
1
|
-
h1.
|
1
|
+
h1. ActiveSms
|
2
2
|
|
3
3
|
h2. What
|
4
4
|
|
5
|
+
Active SMS is a framework for creating and sending SMS messages.
|
5
6
|
|
6
7
|
h2. Installing
|
7
8
|
|
8
9
|
<pre syntax="ruby">sudo gem install activesms</pre>
|
9
10
|
|
10
|
-
h2.
|
11
|
+
h2. Demonstration of usage
|
11
12
|
|
13
|
+
TBD.
|
12
14
|
|
13
|
-
h2.
|
15
|
+
h2. Supported Gateways
|
14
16
|
|
17
|
+
Active SMS will require a valid account from a third party SMS gateway to
|
18
|
+
send or receive SMS messages. The following gateways are currently supported:
|
15
19
|
|
20
|
+
* BulkSMS[http://www.bulksms.com]
|
21
|
+
* Clickatell[http://www.clickatell.com]
|
22
|
+
* Simplewire[http://www.simplewire.com] (requires jruby)
|
16
23
|
|
17
|
-
|
24
|
+
Not all features are supported by all gateways.
|
18
25
|
|
19
|
-
|
26
|
+
h3. Simplewire Configuration
|
20
27
|
|
21
|
-
|
28
|
+
* Make sure you are using jruby
|
29
|
+
* Make sure swsms.jar is in your classpath (Download at: "http://www.simplewire.com/developers/sdk/java/":http://www.simplewire.com/developers/sdk/java/)
|
30
|
+
* Add the following configuration code to the rails environment.
|
22
31
|
|
23
|
-
|
32
|
+
<pre syntax="ruby">
|
33
|
+
ActiveSms::Base.establish_connection(
|
34
|
+
:adapter => "simplewire",
|
35
|
+
:subscriber_id => "id",
|
36
|
+
:subscriber_password => "password"
|
37
|
+
)
|
38
|
+
|
39
|
+
</pre>
|
24
40
|
|
25
|
-
|
41
|
+
h2. Forum
|
26
42
|
|
27
|
-
|
43
|
+
"http://rubyforge.org/forum/?group_id=2923":http://rubyforge.org/forum/?group_id=2923
|
28
44
|
|
29
45
|
h2. License
|
30
46
|
|
31
47
|
This code is free to use under the terms of the MIT license.
|
32
48
|
|
33
|
-
h2.
|
49
|
+
h2. Support
|
34
50
|
|
35
|
-
|
51
|
+
You can find the Active SMS RubyForge page at "http://rubyforge.org/projects/activesms":http://rubyforge.org/projects/activesms.
|
data/website/template.rhtml
CHANGED
@@ -36,10 +36,7 @@
|
|
36
36
|
<a href="<%= download %>" class="numbers"><%= version %></a>
|
37
37
|
</div>
|
38
38
|
<%= body %>
|
39
|
-
|
40
|
-
<a href="mailto:drnicwilliams@gmail.com">Dr Nic</a>, <%= modified.pretty %><br>
|
41
|
-
Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
|
42
|
-
</p>
|
39
|
+
|
43
40
|
</div>
|
44
41
|
|
45
42
|
<!-- insert site tracking codes here, like Google Urchin -->
|
metadata
CHANGED
@@ -3,7 +3,7 @@ rubygems_version: 0.9.2
|
|
3
3
|
specification_version: 1
|
4
4
|
name: activesms
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0
|
6
|
+
version: 0.6.0
|
7
7
|
date: 2007-07-26 00:00:00 -07:00
|
8
8
|
summary: Active SMS is a framework for sending and receiving SMS messages
|
9
9
|
require_paths:
|
@@ -34,15 +34,34 @@ authors:
|
|
34
34
|
- Ben Curren
|
35
35
|
- Dean Mao
|
36
36
|
files:
|
37
|
+
- CHANGELOG
|
37
38
|
- History.txt
|
38
39
|
- License.txt
|
40
|
+
- MIT-LICENSE
|
39
41
|
- Manifest.txt
|
40
42
|
- README.txt
|
41
43
|
- Rakefile
|
44
|
+
- generators/sms/USAGE
|
45
|
+
- generators/sms/sms_generator.rb
|
46
|
+
- generators/sms/templates/fixture.rhtml
|
47
|
+
- generators/sms/templates/model.rb
|
48
|
+
- generators/sms/templates/unit_test.rb
|
49
|
+
- init.rb
|
42
50
|
- lib/activesms.rb
|
51
|
+
- lib/activesms/adv_attr_accessor.rb
|
52
|
+
- lib/activesms/base.rb
|
53
|
+
- lib/activesms/connection_adapters/abstract_adapter.rb
|
54
|
+
- lib/activesms/connection_adapters/bulk_sms_adapter.rb
|
55
|
+
- lib/activesms/connection_adapters/clickatell_adapter.rb
|
56
|
+
- lib/activesms/connection_adapters/simplewire_adapter.rb
|
57
|
+
- lib/activesms/connections.rb
|
58
|
+
- lib/activesms/exceptions.rb
|
59
|
+
- lib/activesms/sms.rb
|
60
|
+
- lib/activesms/validations.rb
|
43
61
|
- lib/activesms/version.rb
|
44
62
|
- scripts/txt2html
|
45
63
|
- setup.rb
|
64
|
+
- test/connection_adapters/test_simplewire_adapter.rb
|
46
65
|
- test/test_activesms.rb
|
47
66
|
- test/test_helper.rb
|
48
67
|
- website/index.html
|