activesms 0.0.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ *0.0.1*
2
+
3
+ * Initial release [Robert Cottrell]
@@ -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.
@@ -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,11 @@
1
+ class <%= class_name %> < ActiveSms::Base
2
+ <% actions.each do |action| -%>
3
+
4
+ def <%= action %>
5
+ @recipients = ''
6
+ @from = ''
7
+ @body = "<%= class_name %>#<%= action %>"
8
+ @options = {}
9
+ end
10
+ <% end -%>
11
+ end
@@ -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,2 @@
1
+ require 'activesms'
2
+ ActiveSms::Base.logger = RAILS_DEFAULT_LOGGER
@@ -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,11 @@
1
+ module ActiveSms
2
+ class Sms
3
+ attr_accessor :recipients
4
+ attr_accessor :from
5
+ attr_accessor :body
6
+
7
+ def to_s
8
+ "#<#{self.class.name} @recipients=#{recipients.inspect} @from=#{from.inspect} @body=#{body.inspect}>"
9
+ end
10
+ end
11
+ 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
@@ -1,8 +1,8 @@
1
1
  module ActiveSms #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 0
5
- TINY = 2
4
+ MINOR = 6
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -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
- activesms
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>activesms</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>The basics</h2>
49
+ <h2>Demonstration of usage</h2>
47
50
 
48
51
 
49
- <h2>Demonstration of usage</h2>
52
+ <p><span class="caps">TBD</span>.</p>
50
53
 
51
54
 
52
- <h2>Forum</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
- <p><a href="http://groups.google.com/group/activesms">http://groups.google.com/group/activesms</a></p>
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><span class="caps">TODO</span> &#8211; create Google Group &#8211; activesms</p>
69
+ <p>Not all features are supported by all gateways.</p>
59
70
 
60
71
 
61
- <h2>How to submit patches</h2>
72
+ <h3>Simplewire Configuration</h3>
62
73
 
63
74
 
64
- <p>Read the <a href="http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/">8 steps for fixing other people&#8217;s code</a> and for section <a href="http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/#8b-google-groups">8b: Submit patch to Google Groups</a>, use the Google Group above.</p>
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
- <p>The trunk repository is <code>svn://rubyforge.org/var/svn/activesms/trunk</code> for anonymous access.</p>
82
+ <pre syntax="ruby">
83
+ ActiveSms::Base.establish_connection(
84
+ :adapter =&gt; "simplewire",
85
+ :subscriber_id =&gt; "id",
86
+ :subscriber_password =&gt; "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>Contact</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 -->
@@ -1,35 +1,51 @@
1
- h1. activesms
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. The basics
11
+ h2. Demonstration of usage
11
12
 
13
+ TBD.
12
14
 
13
- h2. Demonstration of usage
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
- h2. Forum
24
+ Not all features are supported by all gateways.
18
25
 
19
- "http://groups.google.com/group/activesms":http://groups.google.com/group/activesms
26
+ h3. Simplewire Configuration
20
27
 
21
- TODO - create Google Group - activesms
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
- h2. How to submit patches
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
- Read the "8 steps for fixing other people's code":http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/ and for section "8b: Submit patch to Google Groups":http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/#8b-google-groups, use the Google Group above.
41
+ h2. Forum
26
42
 
27
- The trunk repository is <code>svn://rubyforge.org/var/svn/activesms/trunk</code> for anonymous access.
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. Contact
49
+ h2. Support
34
50
 
35
- Comments are welcome. Send an email to "FIXME full name":mailto:FIXME email.
51
+ You can find the Active SMS RubyForge page at "http://rubyforge.org/projects/activesms":http://rubyforge.org/projects/activesms.
@@ -36,10 +36,7 @@
36
36
  <a href="<%= download %>" class="numbers"><%= version %></a>
37
37
  </div>
38
38
  <%= body %>
39
- <p class="coda">
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.2
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